setState can be async. There is a step between when we call setState in which our component changes are diffed through a process called reconciliation. Lets say we have a user that types in an input field: (1) User types in input field, (2) Reconciliation, (3) Input Component, (4) setState invoked, (5) Input Component re-renders
If I had some state that I was expecting to be changed by multiple calls to the setState function, it wouldn’t behave the way that I may have initially intended it to.
counterByThree = () => {
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
};
React will simply ignore a couple of the calls by using this process called batching. This will result in only the last call to setState actually taking place. The solution is using functional setState (the ability to pass a callback function to our setState function).
counterByThree = () => {
this.setState(prevState => ({ count: prevState.count + 1 })),
this.setState(prevState => ({ count: prevState.count + 1 })),
this.setState(prevState => ({ count: prevState.count + 1 }));
};
This way solves both of our problems. We have controlled the batching of these calls to setState by returning a Queue of calls in this fashion. We are also reading from the previous copy of state rather than the current copy.