React: Why pass in setState(), a function instead of an object

The challenge Use State to Toggle an Element wants me to pass in the setState() method a function, instead of an object. And it’s because sometimes setState() calls are batched and run asynchronously and if at the time of updating the state, you need the previous state, you can’t rely on the current state value though.

I could do the challenge but yet I don’t understand why I need to do this? And I tried updating state without passing in a function and passing in an object instead and it works? What’s the idea in this challenge?

1 - How passing a function to setState() method helps preventing several setState() calls from begin batched? And why do I need to know the previous state here?

2 - So far I’ve been passing an object (containing a new value for state properties) to the setState() but now I’m passing a function definition which returns the object. Now is this function definition self-evoking?

As far as I understand the usage of passing function is for clean code.
1 - It is like x = x+1 where the browser js engine first look for the value of the variable and 1. If x was assigned to 2 the engine plus 2 with 1 which result in 3 and assign it to the variable x.
2 - No, it is not a self-evoking function. When the function is passed in, the setState function might have a logic to execute the function. What the setState is focused is that when it got a object it find the key to change from the this.state object, and if it is exit then change it.

Yes for example when you run:

this.setState(prevState => ({stateProp: prevState + 1}))

you need previous state value but how supplying a function instead of an object prevents batching??

If the new state depends on the previous state it is always safer to use an updater function. You may or may not see any bugs without it, but that doesn’t mean it can’t happen.

React docs: setState()

Both state and props received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with state.

Right, there can be an issue with state setting not happening in sequence, and sometimes being combined.

As I understand React …

If I do:

this.setState({ foo: 1 });
this.setState({ foo: 1 });
this.setState({ foo: 1 });
this.setState({ foo: 1 });
this.setState({ foo: 1 });

There is no guarantee when they will be run. I think the order is guaranteed. Furthermore, I think that inside certain lifecycle methods, these may get batched into one call since they are all the same, in a process called “batching”. This works if you are setting a constant value, but if it is an increment, then batching them would be disastrous.

this.setState({ foo: + 1 });
this.setState({ foo: + 1 });
this.setState({ foo: + 1 });
this.setState({ foo: + 1 });
this.setState({ foo: + 1 });

Obviously if those get batched, that’s bad. Furthermore, since setState is asynchronous, you have no way of knowing that the first state update What if they all run in parallel? Then that value effectively only gets run once.

There are other reasons, but I’m probably not smart enough to understand and explain them well.

In any case, the functional setState solves these problems. In general I have these two rules:

  1. If you are giving it a constant value (nothing based on state or props) then you can use an object, and you are not going to be calling it in rapid succession.
  2. Use a function for every other case, e.g., when you are basing it the previous state/props, or when it is something that may be called multiple times in a very short period of time.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.