Vatsal A Mehta
Vatsal A Mehta

Reputation: 430

Why useEffect not updating state?

The structure of my application is :

When the user clicks on StartQuiz button in<Home> component,he is directed to the '/quiz' route. <Quiz> component is rendered after that.

My <Quiz> component is supposed to get the questions from the App component but is not getting that. <App> component gets the questions from the <Home> Component..

The Code is as follows:

Home.js file:

 import ErrorMessage from '../errormessage';

const Home = (props) => {
  const {name,setName,fetchQuestions}=props;
  const [category,setCategory]=useState("");
  const [difficulty,setDifficulty]=useState("");
  const [error,setError]=useState(false);
  const history=useNavigate();
  const handlesubmit=()=>{
    if(!category || !name || !difficulty)
     setError(true);
    else
     {
       fetchQuestions(category,difficulty);
       history('/quiz')                //pushes it in the quiz route
     }
  }
  return (
  <div className="content">
      <div className="settings">
          <span style={{fontSize:30}}>Quiz Settings</span>
      </div>
      <div className="settingsselect">
        {error && <ErrorMessage></ErrorMessage>}
        <TextField label="Enter Your Name" variant="outlined" onChange={(e)=>setName(e.target.value)} value={name}/>
        <TextField id="outlined-select-currency" select label="Select Category" variant="outlined" onChange={(e)=>setCategory(e.target.value)} value={category}>
         {
           Categories.map((cat)=>{
             return(
           <MenuItem key={cat.category}  value={cat.value}>{cat.category}</MenuItem>);
          })
         }
        </TextField>
        <TextField  select label="Select Difficulty" onChange={(e)=>setDifficulty(e.target.value)} value={difficulty}>
          <MenuItem label="Easy" value="easy">Easy</MenuItem>
          <MenuItem label="Medium" value="medium">Medium</MenuItem>
          <MenuItem label="Hard" value="hard">Hard</MenuItem>
        </TextField>
        <Button variant="contained" color="primary" onClick={handlesubmit}>Start Quiz</Button>
      </div>
      <img src="question.svg" className="banner"></img>
  </div>
  );
};

export default Home;

App.js file:

 const [questions,setQuestions]=useState();
    useEffect(()=>{
      console.log("Questions have changed");
    },[questions]);
    const fetchQuestions=async(category,difficulty)=>{
       const {data}=await axios(`https://opentdb.com/api.php?amount=10&category=${category}&difficulty=${difficulty}&type=multiple`);
       setQuestions(data.results);
    }
return (
    <BrowserRouter>
     <div className="App" style={{backgroundImage: "url(./ques1.png)"}}>
      <Header/>
       <Routes>
        <Route path="/home" exact element={<Home name={name} setName={setName} fetchQuestions={fetchQuestions}/>}></Route>
        <Route path="/quiz" exact element={<Quiz name={name} questions={questions} score={score} setScore={setScore} />}></Route>
       </Routes>
      <Footer></Footer>
     </div>
    </BrowserRouter>
  );
}

export default App;

Quiz.js file:

const Quiz = (props) => {
  

  const {name,questions,score,setScore}=props;
  const [options,setOptions]=useState();
  const [currentQuestion,setCurrentQuestion]=useState(0);
  
 
  return (
  <div className='quiz'>
    <span className="subtitle">Welcome ,{name}</span>
    <div className="questionInfo">
      <Question questions={questions} currentQuestion={currentQuestion} setCurrentQuestion={setCurrentQuestion} options={options}/>
    </div>
  </div>
  );
};

export default Quiz;

But Im getting undefined when doing console.log(questions) in the <Quiz> component..

please figure out the issue..

Upvotes: 2

Views: 1829

Answers (1)

Fody
Fody

Reputation: 31862

When you call fetchQuestions(category,difficulty) in handleSubmit you need to await it there as well.

The await inside fetchQuestions does not extend outside of the function, so making handleSubmit async as well will properly await before navigating

// Home

const handlesubmit = async () => {
  if(!category || !name || !difficulty) {
    setError(true);
  } else {
    await fetchQuestions(category,difficulty);
    history('/quiz')              
  }
}

Next, in Quiz you will need useState() and useEffect() to respond to the change of props.questions.


// Quiz

import React, {useState, useEffect} from 'react'

const Quiz = (props) => {

  const [questionsDisplay, setQuestionsDisplay] = useState()

  useEffect(() => {
    const display = props.questions.map((q,idx) => (<div key={idx}>{q.question}</div>))
    setQuestionsDisplay(display)
  }, [props.questions])

  return (
  <div className='quiz'>
    <span className="subtitle">Welcome ,{name}</span>
    <div className="questionInfo">
      {questionsDisplay}
    </div>
  </div>
  );
};

export default Quiz;

Upvotes: 1

Related Questions