As Rikin explained, setState
batches them together and only executes the last one... And yes setState
is async and does take a callback so if you wanted your expected result you'd do this instead:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 5 };
this.handleReset = this.handleReset.bind(this);
}
handleReset() {
this.setState({ count: 0 },
/* here is you callback */
() => this.setState({ count: this.state.count + 1 }))
}
render() {
return (
<div>
<div>{this.state.count}</div>
<button onClick={this.handleReset}>reset</button>
</div>
);
}
}
Hope it helps... Here's a live demo: https://stackblitz.com/edit/react-dbc11s
setState
calls are batched together thus only the final one makes the update. To explain that scenario let's use OP's example with some more similar hardcoded updates as:
handleReset() {
this.setState({ count: 0 })
this.setState({ count: 10 })
this.setState({ count: 100 })
this.setState({ count: this.state.count + 1 })
}
What happens above under the hood is you can think of it as:
Object.assign(
previousState, // { count: 5 }
{count: 0}, // { count: 0 }
{count: 10}, // { count: 10 }
{count: 100}, // { count: 100 }
{count: state.count + 1} // { count: 5 + 1}
)
Object.assign overwrites value of the count
and thus only last value makes the final update which happens to be 6
In case if you want to use prior state's value, you would have to rely on functional setState
method which uses existing state value at the time of execution and then performs update operation on it.
Both scenarios demo here: https://codesandbox.io/s/musing-rhodes-jsf6b