I'm creating a Quiz App. This is the Quiz Page Code. Quiz DB Document contains a QuizQuestions
Array which has question ids. Then I fetch specific question from MCQ/Question DB. Fetching MCQ takes time and when I console.log
fetched data. First and second time data in undefined then its viewable. Due to this I'm unable to display it as it cause TypeError: Cannot read properties of undefined mcqOptions
How can I fix this?
`
import React, { useEffect, useState } from "react";
import shuffleMcq from "../components/shuffleMcq";
const QuizTakePage = ({ match }) => {
const reqUrl = match.params.path; //Getting Quiz ID From URL
const [quizInfo, setQuizInfo] = useState({
"q_title":"",
"q_seo_description":"",
"q_questions":[],
"q_tags":[],
"m_subject":"", })
//const fetchQuizData = fetch();
useEffect(() => {
const fetchQuizData = async () => {
const reqApiUrl = '/quiz/api/qid/' reqUrl;
const fetchedApiResult = await fetch(reqApiUrl);
const resultJson = await fetchedApiResult.json();
setQuizInfo(resultJson);
}
fetchQuizData(); }, []);
// Quiz Data START
const quizTitle = quizInfo.q_title;
const quizDesc = quizInfo.q_seo_description;
const quizQuestions = quizInfo.q_questions;
// Quiz Data END
// MCQ Data START
const [currentQuestion, setCurrentQuestion] = useState(0);
const requestedQuestion = quizQuestions[currentQuestion];
const [mcqInfo, setMcqInfo] = useState({
"m_title":"",
"m_question":"",
"m_alternatives":[],
"m_language":"", })
useEffect(() => {
const fetchApiResponse = async () => {
const reqApiUrl = '/mcq/api/mid/' requestedQuestion;
const fetchedApiResult = await fetch(reqApiUrl);
const resultJson = await fetchedApiResult.json();
setMcqInfo(resultJson);
}
fetchApiResponse(); }, [requestedQuestion]);
//const mcqLanguage = mcqInfo.m_language;
const mcqQuestion = mcqInfo.m_question;
const mcqOptions = mcqInfo.m_alternatives;
console.log(mcqOptions);
return (
<>
<h1>{quizTitle}</h1>
<p>{quizDesc}</p>
</>
);
};
export default QuizTakePage;
CodePudding user response:
A simple mistake was caused the issue.
You defined your state variables before the component did mount (on setState initialize) so the default value must be shown and not get the undefined
but you define the default values in the wrong way. so change them in this way:
const [mcqInfo, setMcqInfo] = useState({
m_title : "",
m_question : "",
m_alternatives : [],
m_language : "",
})
const [quizInfo, setQuizInfo] = useState({
q_title : "",
q_seo_description : "",
q_questions : [],
q_tags : [],
m_subject : "",
})
In the objects, the key
doesn't need a quotation mark.
CodePudding user response:
The reason you're getting undefined
for the first and second time is due to the fact that useEffect
would've not been executed by then. useEffect
runs when the component is rendered and mounted for the first time, and then subsequent executions are made when there is a change in dependency array (If there are any dependencies).
You could get rid of the error by rendering the dynamic content conditionally, i.e, displaying it when the data has been fetched.
return (
<>
<h1>{quizTitle.length>0 ? quizTitle : "Loading Question"}</h1>
<p>{quizDesc.length>0 ? quizDesc: "Loading Description"}</p>
<ul>
{mcqOptions && mcqOptions.length>0 && mcqOptions.map(option=>{
return(<li key={Math.random()}>{option}</li>) //Using Math.random() for key to ensure all the mapped items have an unique key
}
}
</ul>
</>
);
Alternatively, if your mcqOptions
is an array of objects
you can map
it accordingly, for instance, something like this,
<ul>
{mcqOptions && mcqOptions.length>0 && mcqOptions.map(mcqOption=>{
return(<li key={mcqOption.id}>{mcqOption.text}</li>) //Use the properties accordingly, this is an example only.
}
}
</ul>