so i'm basically trying to create a quiz app where i need to keep a track of score meaning how many times a user has clicked the right answer button,
so the issue is i've implemeted a logic about whenever a user clicks as follows; and i wanted to add an increment state when ever
i.id === selectedAnsId && i.answer === correctAns ? {
setScore(prev => prevScore 1)
}
Page1.jsx:
function handleSelect(id, selectedAnsId) {
setQuizData((prevQuizData) => {
return prevQuizData.map((question) => {
const correctAns = question.correct_answer;
return question.id === id
? {
...question,
answers: question.answers.map((i) => {
return i.id === selectedAnsId
? {
...i,
selectedAns: i.answer,
isSelected: !i.isSelected
}
//the condition below is when i want to increment my state
: i.id === selectedAnsId && i.answer === correctAns
? {
...answer,
selectedAns: i.answer,
correctAns: selectedAns,
isSelected: !i.isSelected, /
//here i want to increment my state
}
: i.id === selectedAnsId && i.answer !== correctAns
? {
...answer,
selectedAns: i.answer,
isSelected: true
}
: { ...i, isSelected: false };
})
}
: question;
});
});
console.log(count);
}
so i tried to increment inside these dot fucntion, but the state did not change instead it kept logging 0 ,
i want to know a solution to increment (if posiible inside my ...fucntion) a state when the condition selectedAns is === correctAns is met, or even if it is possible to increment a state inside dot dunction
P.S i've even tried to increment it outside the dot fucntion
CodePudding user response:
React setStates are async. It means that your values are not updated immediately after your setState.
You're doing your setState in a loop. So when you update your state value, the next round of the loop executes faster than the time which is required for the component to use the updated value of that state.
In order to fix your issue, you can use another local variable and update that variable instead of your state and then finally after your loop, set your state:
function handleSelect(id, selectedAnsId) {
//Added
let newCount = count;
setQuizData((prevQuizData) => {
return prevQuizData.map((question) => {
const correctAns = question.correct_answer;
if(question.id === id) {
return {
...question,
answers: question.answers.map((i) => {
if(i.id === selectedAnsId) {
return {
...i,
selectedAns: i.answer,
isSelected: !i.isSelected
};
} else if(i.id === selectedAnsId && i.answer === correctAns) {
//Added
newCount ;
return {
...answer,
selectedAns: i.answer,
correctAns: selectedAns,
isSelected: !i.isSelected,
};
} else if(i.id === selectedAnsId && i.answer !== correctAns) {
return {
...answer,
selectedAns: i.answer,
isSelected: true
};
} else {
return { ...i, isSelected: false };
}
})
}
} else {
return question;
}
});
});
//Added
setCount(newCount);
console.log(newCount);
}
And you can see your changes on count using useEffect:
useEffect(() => {
console.log(count);
}, [count]);
CodePudding user response:
If you necessarily want to increment at the place where you placed the comment, you could add a immediately invoked function like this:
function handleSelect(id, selectedAnsId) {
setQuizData((prevQuizData) => {
return prevQuizData.map((question) => {
const correctAns = question.correct_answer;
return question.id === id
? {
...question,
answers question.answers.map((i) => {
return i.id === selectedAnsId
? {
...i,
selectedAns: i.answer,
isSelected: !i.isSelected,
}
: //the condition below is when i want to increment my state
i.id === selectedAnsId && i.answer === correctAns
? (() => {
//here i want to increment my state
setScore((prev) => prevScore 1);
return {
...answer,
selectedAns: i.answer,
correctAns: selectedAns,
isSelected: !i.isSelected,
};
})()
: i.id === selectedAnsId && i.answer !== correctAns
? {
...answer,
selectedAns: i.answer,
isSelected: true,
}
: { ...i, isSelected: false };
}),
}
: question;
});
});
}
But I think it would be way better to imply from the selected answer whether it was correct, and increment the score before the return
part inside .map()
, somewhat like this:
function handleSelect(id, selectedAnsId) {
setQuizData((prevQuizData) => {
return prevQuizData.map((question) => {
const correctAns = question.correct_answer;
const hasUserAnsweredCorrectly =
i.id === selectedAnsId && i.answer === correctAns;
if (hasUserAnsweredCorrectly) {
setScore((prev) => prevScore 1);
}
return question.id === id
? {
...question,
answers: question.answers.map((i) => {
return i.id === selectedAnsId
? {
...i,
selectedAns: i.answer,
isSelected: !i.isSelected,
}
:
hasUserAnsweredCorrectly
? {
...answer,
selectedAns: i.answer,
correctAns: selectedAns,
isSelected: !i.isSelected,
}
: i.id === selectedAnsId && i.answer !== correctAns
? {
...answer,
selectedAns: i.answer,
isSelected: true,
}
: { ...i, isSelected: false };
}),
}
: question;
});
});
}