0

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:

TypeError on 'category' in 'Quiz.js' StackTrace

brohjoe
  • 854
  • 4
  • 17
  • 39
  • 1
    Your screengrab shows the questions is an empty array, so there is no element at the index and it has no property. Were you expecting it to have values in the question array at that point? – Nikki9696 Jan 27 '22 at 21:49
  • 1
    note that empty arrays are truthy. https://stackoverflow.com/questions/19146176/why-do-empty-javascript-arrays-evaluate-to-true-in-conditional-structures – Nikki9696 Jan 27 '22 at 21:51
  • Yes, there should have been data there...I noticed it was empty but didn't make the connection. I thought the error was preventing the data from coming through, but its the other way around. – brohjoe Jan 27 '22 at 22:04
  • Guess I have to figure out why the data isn't being retrieved. I tested the request api using Postman and Postman retrieved the data just fine. Maybe there is something wrong with the fetchQuestions function in 'App.js.' My fetchQuestions function matches the tutorial though. – brohjoe Jan 27 '22 at 22:05
  • The error may have prevented it. Fix that and see if the useEffect kicks in and hydrates your array =) – Nikki9696 Jan 27 '22 at 22:06
  • actually I dont see your fetch being called. maybe i'm missing it. – Nikki9696 Jan 27 '22 at 22:07
  • 1
    Now that I have new info to work with, I will go back over it and see where the GET isnt happening. – brohjoe Jan 27 '22 at 22:09

0 Answers0