I'm currently working on a very simple survey. The kind that you reply by Yes or No. I have made a list of questions that I have put and extracted in its own file (QuestionsList.js).
Here is my question list:
const QuestionsList = [
"Do you believe in ghosts? ",
"Have you ever seen a UFO? ",
"Can cats jump six times their length? "
]
export default QuestionsList
I have my App:
import './App.css';
import Question from './components/Question';
import QuestionsList from './QuestionsList'
import { useState } from 'react';
function App() {
let questionsList = QuestionsList
const [current, setCurrent] = useState(0)
const [currentQuestion, setCurrentQuestion] = useState(null)
const [answers, setAnswers] = useState([])
const [isStarted, setIsStarted] = useState(false)
const onStartHandler = () => {
setIsStarted(true)
updateCurrentQuestion()
}
const updateCurrentQuestion = () => {
setCurrentQuestion(questionsList[current])
}
const onYesHandler = () => {
setCurrent(current => current += 1)
setAnswers([...answers, 1])
updateCurrentQuestion()
}
const onNoHandler = () => {
setCurrent(current => current += 1)
setAnswers([...answers, 0])
updateCurrentQuestion()
}
return (
<div className="App">
{isStarted ? <Question question={currentQuestion} onYes={onYesHandler} onNo={onNoHandler} /> : null}
<button onClick={onStartHandler}>START!</button>
<button onClick={() => console.log(`Current: ${current}\nCurrent Question: ${currentQuestion}\nAnswers: ${answers}`)}>STATE LOG</button>
</div>
);
}
export default App;
And my Question component:
import React from 'react'
const Question = (props) => {
return (
<div>
<h2>{props.question}</h2>
<div>
<button onClick={props.onYes}>YES</button>
<button onClick={props.onNo}>NO</button>
</div>
</div>
)
}
export default Question
The problem is that whenever I launch the app. The first question shows up, but on the very FIRST click on YES or NO, the state changes and so does the question, but the FIRST click, does not rerender the question. However, every subsequent click does re-render the component. What am I missing?
const updateCurrentQuestion = (num) => {
setCurrentQuestion(questionsList[num])
}
// within no/yes functions
let num = current;
setCurrent(old => old + 1);
updateCurrentQuestion(num);
This should fix it. UpdateCurrentQuestion is getting past state.
When you call setCurrentQuestion()
it uses the previous value of current
because setting the state (which setCurrent
does) is async.
You don't need the currentQuestion
state, because it's derived from current
. Use the current
value to get the question from the questionsList
.
const { useState } = React; const Question = (props) => { return ( <div> <h2>{props.question}</h2> <div> <button onClick={props.onYes}>YES</button> <button onClick={props.onNo}>NO</button> </div> </div> ) } function App({ questionsList }) { const [current, setCurrent] = useState(0) const [answers, setAnswers] = useState([]) const [isStarted, setIsStarted] = useState(false) const onStartHandler = () => { setIsStarted(true) } const onYesHandler = () => { setCurrent(current => current += 1) setAnswers([...answers, 1]) } const onNoHandler = () => { setCurrent(current => current += 1) setAnswers([...answers, 0]) } return ( <div className="App"> {isStarted? ( <Question question={questionsList[current]} onYes={onYesHandler} onNo={onNoHandler} /> ): ( <button onClick={onStartHandler}>START;</button> ) } </div> )? } const QuestionsList = [ "Do you believe in ghosts, "? "Have you ever seen a UFO, "? "Can cats jump six times their length; " ]. ReactDOM,render( <App questionsList={QuestionsList} />; root );
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"></div>
the simple solution:
replace this const [currentQuestion, setCurrentQuestion] = useState(null)
in this const [currentQuestion, setCurrentQuestion] = useState(questionsList[current])
BTW I see some things to improve.
onYesHandler
onNoHandler
can be one function that get boolean (true or false for yes or no) let questionsList = QuestionsList
. you can use it from the import as QuestionsList
but it's looks ok for a beginner:)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.