React: multiple `setState` calls in async callbacks trigger multilple updates

Created on 13 Aug 2019  路  12Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?

bug

What is the current behavior?

When using usingState hook, mutiple setState calls in async callbacks will trigger multiple updates and useEffects.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

https://codesandbox.io/s/react-async-set-state-bug-zsztm

Click 'sync' button, countA and countB will be updated at the same time. The useEffect will run only ONCE with the updated countA and countB.

Click 'async' button, countA and countB will be updated in sequence. The useEffect will run TWICE with the updated countA and old countB at the first time and both updated values at the second time.

What is the expected behavior?

The two setStates should only triger one update.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

16.9.0

Most helpful comment

https://github.com/facebook/react/issues/16387#issuecomment-521623662

(Btw this is how it always worked, and is unrelated to Hooks)

All 12 comments

related topic
https://github.com/facebook/react/issues/14259

You can use ReactDOM.unstable_batchedUpdates to ensure batched update.
https://codesandbox.io/s/react-async-set-state-bug-7jcgx

By "update", do you mean render call or the state update itself? I clicked all three buttons many times, got both A & B to 100+ and their values were equal.

If you inspect the console and compare the two codesandbox examples you should see a difference.

By update I mean how many times the useEffect is called.

The usage of ReactDOM.unstable_batchedUpdates solves the expected behaviour.

What is the expected behavior?
The two setStates should only trigger one update.

@kunukn So you mean I should not assume that multiple setState will or will not be batched into a single update?

@wangcheng678 could you please show a link to the documentation where it says that multiple setState calls will result to a single update?

@miraage My point is the behavior is different in sync and async callbacks.

@wangcheng678

  • this doc is for class components, not hooks
  • I can't remember a React version where class component setState guaranteed multiple setState calls resulting in a single update

@miraage
I remember that React.js guaranteed single update.
(https://twitter.com/dan_abramov/status/824309659775467527)
Maybe they're using mechanism of event loop 馃

@TroyTae please read the tweet itself:

It is safe to call setState with a function multiple times. Updates will be queued and later executed in the order they were called.

It means that setState(stateUpdaterFunction) is safe to be enqueued and the order will be guaranteed (order of applying the state updater functions), but setState(partialStateObject) order is not guaranteed.

@miraage
Oh I have misread this issue.
Of course setState is executed multiple times, but I want to say render-update is fired single time!
I'll split my issue as a new one :)

https://github.com/facebook/react/issues/16387#issuecomment-521623662

(Btw this is how it always worked, and is unrelated to Hooks)

Was this page helpful?
0 / 5 - 0 ratings