1

I see that setState is async. So if I were to call:

this.setState({ variable: true });

and immediately call:

this.setState({ variable: false });

before render is called, am I guaranteed that 'variable' will be false when React is finished processing? In other words, are the async operations sync? Will render be called twice, or will 'variable' be overwritten and render called once with variable=false?

Michael
  • 1,177
  • 15
  • 15
  • check this https://stackoverflow.com/questions/36085726/setstate-in-reactjs-is-async-or-sync?rq=1 – Akhil Oct 19 '17 at 15:53
  • Maybe if you call the 2nd setState as a callback function to the setState... – fungusanthrax Oct 19 '17 at 16:03
  • I'm trying to understand the behavior rather than solve a specific problem. A callback from the first setState call would make this sync, of course. I'm more interested in what happens if multiple components are updating the state of a single variable and are unaware of each other. – Michael Oct 19 '17 at 17:04

3 Answers3

3

From the react docs for setState:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

So your logic should not rely on setState execution time. If you like to control render you should consider using shouldComponentUpdate(nextProps, nextState).

Use shouldComponentUpdate() to let React know if a component’s output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.

bennygenel
  • 23,896
  • 6
  • 65
  • 78
1

It is best not to rely upon this behavior. It will only work sometimes and not others.

To reliably set multiple state properties, gather all the updates and set them in a single call:

const changes = {};

if (some logic) { changes.variable = true; }

if (some more logic) { changes.variable = false; }

this.setState(changes);
Brandon
  • 38,310
  • 8
  • 82
  • 87
  • How do you know it will only work sometimes? I can figure out ways of guaranteeing a result, such as the logic you present. But that doesn't explain the underlying behavior. – Michael Oct 19 '17 at 17:50
  • @bennygenel's answer is an excerpt from the docs that answers "how do I know it will only work sometimes" - it clearly states that `setState` is sometimes asynchronous. And the documentation does not make any guarantees about execution order if you make multiple calls. – Brandon Oct 19 '17 at 19:00
  • setState is asynchronous when it has full control over the variable. So in this case, the assumption is it will definitely be asynchronous. But that does not answer the two questions: 1. Will it call render twice, in order, with a true then false for 'variable'? 2. Does false replace true for 'variable' and only a single call to render will occur? The fact that it is the same variable that is being updated makes it a potentially distinct case from updating two random variables and how they might react to each other. – Michael Oct 19 '17 at 19:26
0

Great question! Made me curious as well, so I whipped up this JSFiddle demonstrating this behavior.

React calls render synchronously after your event handler.

Meaning that because your are doing two updates in the same function, it won't re-render until after the function completes. That means that in each render, this.state.variable will be false.

Chase DeAnda
  • 15,963
  • 3
  • 30
  • 41
  • try your test again, but call setState() from setTimeout. – Brandon Oct 19 '17 at 16:31
  • @Brandon well thats an entirely different scenario. `setTimeout` moves the update onto a separate call stack, so that means it won't hold up the render. So you would see `true` first and then `false`. – Chase DeAnda Oct 19 '17 at 16:32
  • 1
    exactly. and the OP didn't say he was running this code from an event handler, so your conclusion might not be correct. – Brandon Oct 19 '17 at 16:34