Flashcards challenge project (redux): Can't render new quizzes on page

Hello everyone,

I am currently working on the flashcards challenge project in the redux section. Here is the link to the project: Flashcards project

I am currently working on the part where I am trying to make a new quiz for a specific topic. However, when I submit the new quiz that I made, the new quiz does not render on the page. I have a feeling that it has something to do with my thunk action creator. I am not sure if I passed the correct values into the action creators, “addTopic” and “addQuizId”, when I dispatched them in the thunk action creator. Here is the code where I wrote the thunk action creator function in quizSlice.js:

import {createSlice} from '@reduxjs/toolkit';
import {addTopic, addQuizId} from '../topics/topicsSlice';
//import {useDispatch} from 'react-redux';
//const dispatch = useDispatch();
export const quizSlice = createSlice(
    {
        name:'quizzes',
        initialState:{
            quizzes:{

            }
        },
        reducers:{
            addQuiz:(state,action) => {
                const {id,name,topicId,cardIds} = action.payload;
                state.quizzes[id] = {
                    id: id,
                    name: name,
                    topicId: topicId,
                    cardIds: cardIds
                }
            }
        }
    }
)
export const thunkActionCreator = (payload) => {
    const {name,topicId,cardIds,id} = payload;
    return (dispatch) => {
      // dispatch multiple actions here
      dispatch(addTopic({id,name}));
      dispatch(addQuizId({topicId}));

    };
};


export const selectQuiz = (state) => {return state.quizzes.quizzes};
export const {addQuiz} = quizSlice.actions;
export default quizSlice.reducer;

And here is the code where I implement the thunk action creator in the “handleSubmit” event handler in NewQuizForm.js:

import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import ROUTES from "../app/routes";
import{useSelector, useDispatch} from 'react-redux';
import {selectTopic} from '../features/topics/topicsSlice';
import { thunkActionCreator } from "../features/quizzes/quizSlice";

export default function NewQuizForm() {
  const [name, setName] = useState("");
  const [cards, setCards] = useState([]);
  const [topicId, setTopicId] = useState("");
  const history = useHistory();
  const topics = useSelector(selectTopic);
  const dispatch = useDispatch();
  const id = uuidv4();

  const handleSubmit = (e) => {
    e.preventDefault();
    if (name.length === 0) {
      return;
    }

    const cardIds = [];
    
    // create the new cards here and add each card's id to cardIds
    // create the new quiz here
    history.push(ROUTES.quizzesRoute());
    dispatch(thunkActionCreator({name,id,topicId,cardIds}));

    
    
  };

  const addCardInputs = (e) => {
    e.preventDefault();
    setCards(cards.concat({ front: "", back: "" }));
  };

  const removeCard = (e, index) => {
    e.preventDefault();
    setCards(cards.filter((card, i) => index !== i));
  };

  const updateCardState = (index, side, value) => {
    const newCards = cards.slice();
    newCards[index][side] = value;
    setCards(newCards);
  };

  return (
    <section>
      <h1>Create a new quiz</h1>
      <form onSubmit={handleSubmit}>
        <input
          id="quiz-name"
          value={name}
          onChange={(e) => setName(e.currentTarget.value)}
          placeholder="Quiz Title"
        />
        <select
          id="quiz-topic"
          onChange={(e) => setTopicId(e.currentTarget.value)}
          placeholder="Topic"
        >
          <option value="">Topic</option>
          {Object.values(topics).map((topic) => (
            <option key={topic.id} value={topic.id}>
              {topic.name}
            </option>
          ))}
        </select>
        {cards.map((card, index) => (
          <div key={index} className="card-front-back">
            <input
              id={`card-front-${index}`}
              value={cards[index].front}
              onChange={(e) =>
                updateCardState(index, "front", e.currentTarget.value)
              }
              placeholder="Front"
            />

            <input
              id={`card-back-${index}`}
              value={cards[index].back}
              onChange={(e) =>
                updateCardState(index, "back", e.currentTarget.value)
              }
              placeholder="Back"
            />

            <button
              onClick={(e) => removeCard(e, index)}
              className="remove-card-button"
            >
              Remove Card
            </button>
          </div>
        ))}
        <div className="actions-container">
          <button onClick={addCardInputs}>Add a Card</button>
          <button>Create Quiz</button>
        </div>
      </form>
    </section>
  );
}

Any ideas as to why I can’t render the new quizzes? Any help is appreciated! Thanks everyone and happy coding :slight_smile:

Hi @codejumper03379
what does your topicSlice look like?
You dispatch objects as payload. I’m not sure if a shorthand works here. But seeing what the topic state and reducer that receive the payload would be relevant here.

Hi @mirja_t

I hope all is well. Thanks for your help! This is my topicSlice.js code:

import {createSlice} from '@reduxjs/toolkit';

export const topicsSlice = createSlice({
    name: 'topics',
    initialState: {
        topics: {

        }
    },
    reducers: {
        addTopic: (state,action) => {
            const { id, name, icon } = action.payload;
            state.topics[id] = {
                id: id,
                name: name,
                icon: icon,
                quizIds: []
            }
        },
        addQuizId: (state,action) => {
            const {quizId, topicId} = action.payload;
            state.topics[topicId].quizIds.push(quizId);
        }
    }
    
    }
)
export const selectTopic = (state) => state.topics.topics;
export const {addTopic, addQuizId} = topicsSlice.actions;
export default topicsSlice.reducer;

Yes, I also have some doubts if I wrote the “addQuizId” reducer correctly. Did I write it right? Thanks again! Take care :slight_smile:

Ok, so you have an addQuiz reducer here:

That is supposed to add the quiz to the other quizzes in the state. But your reducer replaces it with the last item dispatched each time. You don’t copy the previous quizzes from the state. Yet you should at least see one quiz.

But I don’t see that you dispatch the addQuiz action anywhere. In the thunk you just dispatch addQuizId, but that just adds the id of the quiz to the related topic and addTopic.

Step 12 (that’s where you currently are, right?) advises you to dispatch the actions from the previous two steps in the thunkActionCreator. That would be addQuiz from step 10 and addQuizId from step 11.

Hi @mirja_t ,

Thank you for pointing out that I didn’t call the addQuiz action in the thunk action creator. I made the mistake by calling addTopic instead of addQuiz. So I changed that now. Here is my thunk action creator:

export const thunkActionCreator = (payload) => {
    const {name,topicId,cardIds,id} = payload;
    return (dispatch) => {
      // dispatch multiple actions here
      dispatch(addQuiz({id,name,topicId,cardIds}));
      dispatch(addQuizId({topicId}));

    };

However, when I run the code, nothing is still rendered on the quizzes page:

But when I check the Topics page, it shows that my particular topic has quizzes associated with it:

Thanks again for your help! Cheers :slight_smile:

Out of curiosity I wanted to see the values of quizId in the topics object. This is the value that I see when I make a quiz:

The value is null. It seems I’m not passing the quizId correctly. This is my addQuizId reducer:

addQuizId: (state,action) => {
            const {quizId, topicId} = action.payload;
            state.topics[topicId].quizIds.push(quizId);
        }

Is it correct, the way I am storing the quizId in the topics object?

If you havent’t changed that yet, you dispatch addQuizId only with the topicId as payload.

Then quizId is the ID of the topic and topicId is undefined.

@mirja_t ok thanks! It seems I fixed the quizId problem. Here is my thunk action creator:

export const thunkActionCreator = (payload) => {
    const {name,topicId,cardIds,id} = payload;
    return (dispatch) => {
      // dispatch multiple actions here
      dispatch(addQuiz({id,name,topicId,cardIds}));
      dispatch(addQuizId({quizId:id,topicId:topicId}));

    };

And here are the results:

However, the quizzes still do not render on the quizzes page.

I was thinking I had to pass the quizSlice reducer into store.js as such:

import { configureStore } from "@reduxjs/toolkit";
import {topicsSlice} from "../features/topics/topicsSlice";
import {quizSlice} from "../features/quizzes/quizSlice";

export default configureStore({
  reducer: {
    topics: topicsSlice.reducer,
    quizzes: quizSlice.reducer
  },
});

But nothing still renders on the quizzes page

What does your Quizzes.js look like?

Oh that was the problem! Haha I didn’t pass my selector into Quizzes.js :sweat_smile:

Now it is rendering the quizzes:

Thank you again so much @mirja_t . I couldn’t have solved this problem without you! I wish you all the best :slight_smile:

1 Like

You’re welcome! Happy coding :slight_smile: