为什么 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;
我的应用程序的结构是:
当用户点击 <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;