I'm creating a quiz app following a tutorial.
I'm getting a 'TypeError: Cannot read properties of undefined (reading 'category'). I've noticed there are other SO answers out there with a simular heading, but I didn't see a situation that was comparable enough for me to extrapolate an answer.
There are several components but the error is in the 'Quiz.js' component. It accepts imports from the 'Question.js' component. The 'App' component accepts imports from all components of course. I'm also using axios to interface with a trivia quiz api.
The problem I'm having is that in 'Quiz.js', on the following line, "category" seems to throw an error, but it seems to work in the tutorial code:
<span>{questions[currQues].category}</span>
'Category' is a variable inside 'DropDownData.js.' I changed the component name from 'Categories' to 'DropDownData' because WebStorm didn't present the code in the proper javascript colors, so I changed the name of the component thinking that might fix the problem. I'm not totally sure why, but that worked. The color of the code's font did start rendering correctly after that but I'm still getting the dreaded 'TypeError' error.
Here are the minimum files to understand the problem, but the entire codebase is on github.
App.js
import React, {Component, useState} from 'react';
import ReactDOM from 'react-dom';
import Header from './components/Header/Header'
import './App.css';
import {BrowserRouter, Route, Switch} from "react-router-dom";
import Footer from "./components/Footer/Footer";
import Home from "./components/Home/Home"
import Quiz from "./components/Quiz/Quiz"
import Result from "./components/Result/Result"
import axios from "axios";
function App() {
//created here for common sharing with Quiz page.
const [name, setName] = useState("")
const [questions, setQuestions] = useState()
const [score, setScore] = useState(0)
const fetchQuestions = async (category = "", difficulty = "") => {
const {data} = await axios.get(
`https://opentdb.com/api.php?amount=10${
category && `&category=${category}`}
${difficulty && `&difficulty=${difficulty}`}&type=multiple`
);
setQuestions(data.results)
}
return (
<BrowserRouter>
<div className="App">
<Header/>
<Switch>
<Route path='/' exact>
<Home name={name}
setName={setName}
fetchQuestions={fetchQuestions}/>
</Route>
<Route path='/quiz' exact>
<Quiz
name={name}
questions={questions}
score={score}
setScore={setScore}
setQuestions={setQuestions}
/>
</Route>
<Route path='/result' exact>
<Result/>
</Route>
</Switch>
</div>
<Footer/>
</BrowserRouter>
)
}
export default App;
DropDownData.js
const DropDownData = [
{
category: "General Knowledge",
value: 9,
},
{ category: "Books", value: 10 },
{ category: "Films", value: 11 },
{ category: "Music", value: 12 },
{ category: "Musicals and Theaters", value: 13 },
{ category: "Television", value: 14 },
{ category: "Video Games", value: 15 },
{ category: "Board Games", value: 16 },
{ category: "Science and Nature", value: 17 },
{ category: "Computer", value: 18 },
{ category: "Mathematics", value: 19 },
{ category: "Mythology", value: 20 },
{ category: "Sports", value: 21 },
{ category: "Geography", value: 22 },
{ category: "History", value: 23 },
{ category: "Politics", value: 24 },
// { category: "Art", value: 25 },
{ category: "Celebrities", value: 26 },
{ category: "Animals", value: 27 },
{ category: "Vehicles", value: 28 },
{ category: "Comics", value: 29 },
{ category: "Gadgets", value: 30 },
{ category: "Japanese Anime", value: 31 },
{ category: "Cartoon and Animations", value: 32 },
];
export default DropDownData;
Question.js
import { Button } from "@material-ui/core";
import { useState } from "react";
import ErrorMessage from "../ErrorMessage/ErrorMessage";
import {useHistory} from "react-router-dom/cjs/react-router-dom";
const Question = ({
currQues,
setCurrQues,
questions,
options,
correct,
setScore,
score,
setQuestions,
}) => {
const [selected, setSelected] = useState();
const [error, setError] = useState(false);
const history = useHistory();
const handleSelect = (i) => {
if (selected === i && selected === correct) return "select";
else if (selected === i && selected !== correct) return "wrong";
else if (i === correct) return "select";
};
const handleCheck = (i) => {
setSelected(i);
if (i === correct) setScore(score + 1);
setError(false);
};
const handleNext = () => {
if (currQues > 8) {
history.push("/result");
} else if (selected) {
setCurrQues(currQues + 1);
setSelected();
} else setError("Please select an option first");
};
const handleQuit = () => {
setCurrQues(0);
setQuestions();
};
return (
<div className="question">
<h1>Question {currQues + 1} :</h1>
<div className="singleQuestion">
<h2>{questions[currQues].question}</h2>
<div className="options">
{error && <ErrorMessage>{error}</ErrorMessage>}
{options &&
options.map((i) => (
<button
className={`singleOption ${selected && handleSelect(i)}`}
key={i}
onClick={() => handleCheck(i)}
disabled={selected}
>
{i}
</button>
))}
</div>
<div className="controls">
<Button
variant="contained"
color="secondary"
size="large"
style={{ width: 185 }}
href="/"
onClick={() => handleQuit()}
>
Quit
</Button>
<Button
variant="contained"
color="primary"
size="large"
style={{ width: 185 }}
onClick={handleNext}
>
{currQues > 20 ? "Submit" : "Next Question"}
</Button>
</div>
</div>
</div>
);
};
export default Question;
Quiz.js error here
import {useEffect, useState} from 'react';
import Question from "../../components/Question/Question";
import {CircularProgress} from "@material-ui/core";
import "./Quiz.css"
const Quiz = ({name, score, questions, setQuestions, setScore, correct_answer}) => {
const [options, setOptions] = useState()
const [currQues, setCurrQues] = useState(0)
useEffect(() => {
setOptions(questions &&
handleShuffle([
questions[currQues]?.correct_answer,
...questions[currQues]?.incorrect_answer,]));
}, [currQues, questions]);
console.log("Displaying questions ", questions);
const handleShuffle = (options) => {
return options.sort(() => Math.random() - 0.5);
};
// TODO: sort the questions as well
return (
<div>
<span className="subtitle"> Welcome, {name}></span>
{ questions ? (
<>
<div className="quizInfo">
<span>{questions[currQues].category} < /span>**//error here**
<span>
{/*{questions[currQues].difficulty} */}
Score: {score}
</span>
</div>
<Question //sending to Question component.
currQues={currQues}
setCurrQues={setCurrQues}
questions={questions}
options={options}
correct={questions[currQues]?.correct_answer}
score={score}
setScore={setScore}
setQuestions={setQuestions}
/>
</>
) : (
<CircularProgress
style={{margin: 100}}
color="inherit"
size={150}
thickness={1}
/>
)}
</div>
);
};
export default Quiz;
StackTraces: