TomK
TomK

Reputation: 127

react Async and setting state

I have a total set in my state, initialized to 0.

Here is the function (in is triggered with an input field that gives it the qty parameter in another component):

calculateTotal(qty) {
  if (qty === 1) {
    this.setState({
      total: this.state.total += 250
    })
  }
  else if (qty > 1) {
    this.setState({
      total: qty *= 250
    })
  }
  else {
    this.setState({total: this.state.total})
  }
  console.log(this.state.total);
}

Upvotes: 0

Views: 78

Answers (2)

Jake
Jake

Reputation: 732

For one you only have to call setState once. Also setState is asynchronous as you stated along with the console log so in order to ensure the log is running after you set the state utilize a callback with setstate

calculateTotal(qty) {
  var total;
  if (qty === 1) {
    total = this.state.total + 250; // total = total + 250
  }
  else if (qty > 1) {
    total = (qty * 250);  // total = qty * 250
  }
  else {
    total = this.state.total;
  }
  this.setState({ total }, () => console.log(this.state.total))
}

Upvotes: 0

Ryan H.
Ryan H.

Reputation: 7844

Since you are calling setState, I'm assuming that your code represents one method of some larger component.

setState is an asynchronous operation so your console.log is probably being called before the component state has been updated. However, if you try to console.log in the component's render method, you'll get more predictable results.

Since you should use setState to update your state and not mutate it directly, you should not do this:

this.state.total += 250

This tries to directly update total, effectively trying to bypass setState. You normally want to do something like this instead:

this.setState({
  total: this.state.total + 250
})

However, this is also incorrect because you want to calculate a new state based on a previous state. To be guaranteed to get the previous state (due to the asynchronous nature of setState) you should do this instead:

this.setState((prevState) => {
  return {
    total: prevState.total + 250
  }
})

Also, this.setState({total: this.state.total}) is not necessary. If you do not want to change the state, simply do nothing.

Finally, when the component's state has been updated, the React framework will then re-render your component. Therefore, try to log total in your component's render method. You should then get the values you expect.

Upvotes: 4

Related Questions