I'm building an application that has a quizz section. It's only meant to display one question at a time, and they're coming from an API as an array of questions. I'd like to have a mechanism on the main Quizz component that would know which question is currently being displayed and, when there's a correct answer, move on to the next question. It works fine for the first question, but once I arrive at the second question, React re-renders my component and my state is reset.
function Quizz() {
const [selectedQuestion, setSelectedQuestion] = useState(0);
const handleQuestionAnswer = useCallback((isRejection) => {
setSelectedQuestion(selectedQuestion 1);
}, [setSelectedQuestion]);
return {QuizzData.questions.map((question, i) => {
if (i === selectedQuestion) {
return (
<Question data={question} clickCallback={handleQuestionAnswer} key={i} />
);
}
}
The Question component passes the callback to a child, which then invokes the function.
CodePudding user response:
handleQuestionAnswer
is closing over the initial state value. Use a functional state update to correctly update from previous state instead of whatever is closed over in callback scope.
Example:
const handleQuestionAnswer = useCallback((isRejection) => {
setSelectedQuestion(selectedQuestion => selectedQuestion 1);
}, [setSelectedQuestion]);
See Functional Updates for more details.
General "Rule of Thumb": If the next React state value depends on the previous state value, i.e. incrementing a count, use a functional state update.
CodePudding user response:
Your handleQuestionAnswer useCallback seems to have the wrong dependencies, you probably meant selectedQuestion
instead of setSelectedQuestion
.
As you used the wrong dependencies, your handleQuestionAnswer does not 'update' and is only binded to selectedQuestion=0 (as setSelectedQuestion never update)
configured eslint might have help you notice this issue, so it is worth taking time to set it up !