Reputation: 161
I have tried to read similar solutions for this problem and none of it able to solve my problem. From the console error, it stated that I have an error in this line
this.setState({ submitted: true, finalScore });
I am currently making a quiz app using ReactJS where it has a timer. Which, once the timer reaches to 0 - It will automatically submit the answer.
this is my render
render() {
const { questionBank, submitted, finalScore, minute, second } = this.state;
return (
<Box>
<h2>Pop Quiz!</h2>
<h3>Time remaining: {minute}:{second< 10 ? `0${ second }` : second}</h3>
{ minute === 0 && second === 0
? this.handleSubmit() : <div>{!submitted &&
questionBank.length > 0 &&
questionBank.map(
({ question, answers, correct, questionId }, index) => (
<QuestionBox
key={questionId}
index={index + 1}
question={question}
options={answers}
selected={(answer) =>
this.computeAnswer(answer, correct, questionId)
}
/>
)
)}
{!submitted && (
<Box align="end">
<Button
primary
label="Submit"
onClick={() => this.handleSubmit()}
/>
</Box>
)}
{submitted && <Result score={finalScore} playAgain={this.playAgain} />}
</div>
}
</Box>
);
}
this is my timer
timer = () => {
this.myInterval = setInterval(() => {
const { second, minute } = this.state
if (second > 0) {
this.setState(({ second }) => ({
second: second - 1
}))
}
if (second === 0) {
if (minute === 0) {
clearInterval(this.myInterval)
} else {
this.setState(({ minute }) => ({
minute: minute - 1,
second: 59
}))
}
}
}, 1000)
}
componentDidMount() {
this.getQuestions();
this.timer();
}
and this is handleSubmit
handleSubmit() {
const {
correctQuestionAnswered,
questionBank: { length },
} = this.state;
const { db } = this.props;
const finalScore = ((correctQuestionAnswered / length) * 100).toFixed(2);
const currentdate = new Date();
const dateTime =
currentdate.getDate() +
"/" +
(currentdate.getMonth() + 1) +
"/" +
currentdate.getFullYear() +
" @ " +
currentdate.getHours() +
":" +
currentdate.getMinutes() +
":" +
currentdate.getSeconds();
db.put({
_id: new Date().toJSON(),
submit_datetime: dateTime,
score: finalScore,
});
this.setState({ submitted: true, finalScore }); // <--- This is the line that I get an error
this.forceUpdate();
}
Where did I go wrong that gives me this result? I am still fairly new in reactJS
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state
//Edit:
After tweaking some more, I managed somehow fixed it by moving the submitHandler to the timer when it reaches 00:00 and erase the this.forceUpdate()
within submitHandler. However, I am still not entirely sure why the previous design doesn't work.
Upvotes: 1
Views: 57
Reputation: 61
I didn't go over your code in great detail since you fixed the issue, but I believe it is because you called your state inside the render() method. Each time there is a change (for you always, since you are counting down) your state is stuck in an infinite loop. it should be mentioned in the constructor() or use a tool like redux.
edit: beat to the punch and much more elegantly...
Upvotes: 0
Reputation: 1259
Simple, you are calling setState in your render
method, which is not allowed in React.
This line of code in your render
method is illegally causing the setState to be called:
{ minute === 0 && second === 0
? this.handleSubmit()
You should move this state check into a componentDidUpdate()
method in your component's class. In short, componentDidUpdate()
is called whenever the props or state of your component changes (in other words, whenever your component renders). Learn about componentDidUpdate() here
Here you should check the minute
and second
state, and call the handleSubmit() method accordingly:
componentDidUpdate() {
if(this.state.minute === 0 && this.state.second === 0) {
this.handleSubmit()
}
}
And remove the minute === 0 && second === 0
ternary from the render method.
If you have any problems while implementing my solution, please let me know in a comment.
Upvotes: 2