Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS onClick state change one step behind

I'm building a very primitive quiz app with ReactJS and I'm having trouble updating the state of my Questions component. Its behavior is it renders the correct index of the questions array to the DOM despite this.state.questionNumber always being one step behind in handleContinue():

import React from "react"

export default class Questions extends React.Component {
  constructor() {
    super()
    this.state = {
      questionNumber: 1
    }
  }

  //when Continue button is clicked
  handleContinue() {
    if (this.state.questionNumber > 3) {
      this.props.unMount()
    } else {
      this.setState({
        questionNumber: this.state.questionNumber + 1
      })
      this.props.changeHeader("Question " + this.state.questionNumber)
    }
  }

  render() {
    const questions = ["blargh?", "blah blah blah?", "how many dogs?"]
    return (
      <div class="container-fluid text-center">
        <h1>{questions[this.state.questionNumber - 1]}</h1>
        <button type="button" class="btn btn-primary" onClick={this.handleContinue.bind(this)}>Continue</button>
      </div>
    )
  }
}
like image 751
Jackson Lenhart Avatar asked Dec 02 '22 13:12

Jackson Lenhart


1 Answers

setState() is not necessarily a synchronous operation:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state aft

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

For this reason, this.state.questionNumber may still hold the previous value here:

this.props.changeHeader("Question " + this.state.questionNumber)

Instead, use the callback function that is called once the state transition is complete:

this.setState({
    questionNumber: this.state.questionNumber + 1
}, () => {
    this.props.changeHeader("Question " + this.state.questionNumber)
})
like image 168
TimoStaudinger Avatar answered Dec 06 '22 11:12

TimoStaudinger