Flashcards Challenge: Stuck on step 15

My code updates the state with the new topic, new quiz and displays the newly created quiz on page. But when clicking on to the quiz it redirects to ‘…/quizzes/undefined’ and produces this error:

" TypeError: Cannot read properties of undefined (reading ‘name’) "

 12 |   13 | return (  
14 |   <section>> 
 > 15 |     <h1>{quiz.name}</h1>    
16 |     <ul className="cards-list">  
17 |       {quiz.cardIds.map((id) => (  
18 |         <Card key={id} id={id} />

The error seems to come from the Quiz.js page as when I log the ‘quiz’ variable it returns ‘undefined’. But I’m unsure why it’s undefined as the data is there in the state and even appears when I log the ‘quizzes’ variable 2 lines above. Any ideas?

Quiz.js:

import { Link, useParams } from "react-router-dom"; import Card from "../cards/Card"; import ROUTES from "../../app/routes"; import { useSelector } from "react-redux"; import { selectQuiz } from "./quizzesSlice"; export default function Topic() { const quizzes = useSelector(selectQuiz); // replace this with a call to your selector to get all the quizzes in state console.log(quizzes) //Returns state of quizzes let { quizId } = useParams(); const quiz = quizzes[quizId]; console.log(quiz) //Returns undefined return ( <section> <h1>{quiz.name}</h1> <ul className="cards-list"> {quiz.cardIds.map((id) => ( <Card key={id} id={id} /> ))} </ul> <Link to={ROUTES.newQuizRoute()} className="button center"> Create a New Quiz </Link> </section> ); }

quizzesSlice.js:

import { createSlice } from '@reduxjs/toolkit'; import { addQuizId } from '../topics/topicsSlice'; const quizzesSlice = createSlice({ name: 'quizzes', initialState: { quizzes: {} }, reducers: { addQuiz: (state, action) => { const { quizId } = action.payload; state.quizzes[quizId] = action.payload } } }) export const addQuizThunk = (payload) => { return (dispatch) => { dispatch(addQuiz(payload)); dispatch(addQuizId({ quizId: payload.quizId, topicId: payload.topicId })) } }; export const selectQuiz = state => state.quizzes.quizzes; export const { addQuiz } = quizzesSlice.actions; export default quizzesSlice.reducer

Quizzes.js:

import { Link } from "react-router-dom"; import ROUTES from "../../app/routes"; import { useSelector } from "react-redux"; import { selectQuiz } from "./quizzesSlice"; export default function Quizzes() { const quizzes = useSelector(selectQuiz); // replace this with a call to your selector to get all the quizzes in state return ( <section className="center"> <h1>Quizzes</h1> <ul className="quizzes-list"> {Object.values(quizzes).map((quiz) => ( <Link key={quiz.id} to={ROUTES.quizRoute(quiz.id)}> <li className="quiz">{quiz.name}</li> </Link> ))} </ul> <Link to={ROUTES.newQuizRoute()} className="button"> Create New Quiz </Link> </section> ); }

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 { addQuizThunk } from "../features/quizzes/quizzesSlice"; import { addCard } from "../features/cards/cardsSlice"; 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 handleSubmit = (e) => { e.preventDefault(); if (name.length === 0) { return; } const cardIds = []; // create the new cards here and add each card's id to cardIds cards.forEach((card) => { let cardId = uuidv4(); cardIds.push(cardId); dispatch(addCard({...card, id: cardId})) }) // create the new quiz here dispatch(addQuizThunk({ quizId: uuidv4(), name: name, topicId: topicId, cardIds: cardIds })); history.push(ROUTES.quizzesRoute()); }; 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> ); }

Figured out where I was going wrong, In ‘quizzesSlice.js’ I was returning an object with key ‘quizId’ when it should of been ‘id’.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.