stackjlei stackjlei - 28 days ago 17
Javascript Question

Why does using function inside React's #setState solve async issues?

From the docs, it says "React may batch multiple setState() calls into a single update for performance" so it recommends using a function instead of an object for

setState
's argument. How does this solve the problem?

// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});

// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));

Answer

When you pass in an object to setState, react will take whatever you pass in, create an event that will track what was passed in, and then will eventually update state. As the docs say, if multiple setStates are run, react may batch those together and since its going to happen asynchronously, aka at some point down the road, when you run the first example it may use a this.state.counter that is actually old and cause unexpected side effects.

The second option is considered more safe because it is much like a promise: When you pass in a function, React will only run this function once the state has actually been updated. This ensures that you have correct this.state.counter variable each time you update by using the prevState variable they provide as an argument to the callback.

I haven't myself ran into an issue using the first method but I also haven't tried flooding a bunch of setStates calls at once which I'm sure is when this does come up. The main way I've seen this foul people up is when they are trying to use the new state right after setting state.

for example:

increaseCounter() {
 this.setState({
   counter: this.state.counter + this.props.increment,
 });

 // this will more then likely be the previous value 
 // as setState does not run right away, but asynchronously 
 this.useNewCounter(this.state.counter) 
}

in that example one might expect that when useNewCounter is called that it would be using the latest state, but it will not, the reference will still be pointed at the previous value until react updates the state which will be at some point after this method is called.