1

I am learning reactjs by creating a simple calculator that doubles a given number. When the callback to this.setState is called it has the existing value of this.state.amount and not the new value that was just entered.

  handleAmountChange: function(event) {
    this.setState({amount: event.target.value}, this.calculate());
  },
  calculate: function() {
      this.setState({calculatedAmount: this.state.amount * 2});
  }

What should be I be doing to get the most up to date version for this.state.amount in the calculate function?

https://plnkr.co/edit/FoTEK9PglqhUajq1lLXJ?p=preview

Joel Cunningham
  • 13,620
  • 8
  • 43
  • 49
  • { console.log('callingsetState');this.setState((prevState) => ({count: prevState.count + 1}))}} >Increase – zloctb Aug 18 '17 at 09:53

2 Answers2

2

Take a look at this answer. In short, setState only creates a pending state transition, not an immediate state mutation.

In your case, I think the cleanest approach would be to use refs instead of passing the value of the input to the state and reading from it:

var Calculator = React.createClass({  
  getInitialState: function() {
    return {
      calculatedAmount: 0.0
    };
  },

  calculate: function() {
    this.setState({calculatedAmount: this.refs.myNumber.value * 2});
  },

  render: function(){
    return (
      <div id="calculator">
        <h3>Calculator</h3>
        <input type="text" ref="myNumber" onChange={this.calculate} />
        <span>{this.state.calculatedAmount}</span>
      </div>
    );
  }
});

EDIT: I realized your solution with using a callback is a perfectly valid one but it is not working because you are executing the callback function, instead of passing it. This will do the trick:

handleAmountChange: function(event) {
  this.setState({amount: event.target.value}, this.calculate);
},
calculate: function() {
  this.setState({calculatedAmount: this.state.amount * 2});
}
Community
  • 1
  • 1
Jan Klimo
  • 4,643
  • 2
  • 36
  • 42
  • Thank you for your answer. This seems a much better way to do things. I am still not sure why the setState callback seemed to be called before the state was transitioned though. – Joel Cunningham May 08 '16 at 04:21
  • You're welcome! The difference is between passing `this.calculate()` and `this.calculate` – Jan Klimo May 08 '16 at 04:31
  • Silly mistake by me but I've learnt more about react in doing so. Thanks. – Joel Cunningham May 08 '16 at 05:02
  • @JanKlimo why does this.calculate work and this.calculate() does not ? – aishpant Jul 21 '16 at 07:56
  • You need to pass a reference to the function - without the brackets. If you include the brackets, you would be passing the return value of that function instead. – Jan Klimo Jul 21 '16 at 08:08
0

In your particular case, you can set more than one states at once, i.e. execute the calculation in handleAmountChange.

var Calculator = React.createClass({  
  getInitialState: function() {
    return {
      amount: 0.0,
      calculatedAmount: 0.0
    };
  },
  handleAmountChange: function(e) {
    var input = e.target.value; 
    this.setState({amount: input, calculatedAmount: input * 2});
  },
  render: function(){
    return (
      <div id="calculator">
        <h3>Calculator</h3>
          <input type="text" value={this.state.amount} onChange={this.handleAmountChange} />
          <span>{this.state.calculatedAmount}</span>
      </div>
    );
  }
});

ReactDOM.render(<Calculator />, document.getElementById('container'

));

Wilson Lee
  • 2,631
  • 1
  • 10
  • 6