Why we need to pass a function to React setState() method?

The reason behind for this is that setState() is an asynchronous operation. React batches state changes for performance reasons, so the state may not change immediately after setState() is called. That means you should not rely on the current state when calling setState() since you can't be sure what that state will be. The solution is to pass a function to setState(), with the previous state as an argument. By doing this you can avoid issues with the user getting the old state value on access due to the asynchronous nature of setState().

Let's say the initial count value is zero. After three consecutive increment operations, the value is going to be incremented only by one.

// assuming this.state.count === 0
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
// this.state.count === 1, not 3

If we pass a function to setState(), the count gets incremented correctly.

this.setState((prevState, props) => ({
count: prevState.count + props.increment,
}));
// this.state.count === 3 as expected

(OR)

Why function is preferred over object for setState()?

React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

This counter example will fail to update as expected:

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

The preferred approach is to call setState() with function rather than object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument.

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

January 10, 2019
5538