Description
React version: 18.3.1
Steps To Reproduce
- Create an effect of the following form:
useEffect(() => {
(async () => {
setStateA("foo");
await someAsyncFunctionThatReturnsImmediately();
setStateA("bar");
})();
});
Link to code example: https://codesandbox.io/p/sandbox/react-dev-forked-9m77xd
The current behavior
React will render with the second state update first ("bar"), and then re-render with the first update ("foo"). This only happens when the awaited function returns immediately. If the awaited promise resolves at a later time, the state is updated in the expected order.
In the example, you can observe this happening by clicking the button and looking at the console ("BUG RENDERED!!!😱😱😱"), or by seeing a brief flash of red on the component as it renders inaccurately. The console message triggers every time, the red flash only occurs occasionally. In our actual app we're seeing the render occur every time.
If you adjust the example to instead call await optionalDelay(true)
, the state updates will be applied in order and the component will flash green.
The expected behavior
The state updates should be applied in the order as specified in the code. This was the behavior in React 16, which can be tested in the sandbox.
This appears to be fixed in React 19.0.0-rc.0.
Previously reported in:
- Bug: out of order application of useState changes #25129, which has a wonderfully concise repro https://codesandbox.io/p/sandbox/cocky-fermat-qoiel3.
- Bug: state updates are applied out of order inside useEffect when using Promise.resolve #24649, where this was mentioned as a known issue but no tracking issue was given.