Skip to content

Wait Until Data is Fetched from MongoDB React JS

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?enter image description here `

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;

Answer

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>