为什么 useEffect 不更新状态?

Why useEffect not updating state?

我的应用程序的结构是:

当用户点击 <Home> 组件中的 StartQuiz 按钮时,他被引导至 '/quiz' 路径。 <Quiz> 组件在之后渲染。

我的 <Quiz> 组件应该从 App 组件获取问题,但没有获取。 <App> 组件从 <Home> 组件获取问题..

代码如下:

Home.js 文件:

 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 文件:

 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 文件:

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;

但是我在 <Quiz> 组件中执行 console.log(questions) 时得到 undefined..

请解决问题..

当您在 handleSubmit 中调用 fetchQuestions(category,difficulty) 时,您也需要在那里等待它。

fetchQuestions 中的 await 不会扩展到函数之外,因此使 handleSubmit async 也将在导航前正确等待

// Home

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

接下来,在Quiz中你需要useState()useEffect()来响应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;