react icon indicating copy to clipboard operation
react copied to clipboard

Bug: state updates are applied out of order inside useEffect when using Promise.resolve

Open Dremora opened this issue 2 years ago • 6 comments

When two state updates are scheduled within useEffect, first one directly and second wrapped inside Promise.resolve(), they will be applied out of order. Same behaviour when using queueMicrotask instead. setTimeout(x, 0) doesn't produce the issue.

React version: 18.1.0

This is only happening in Concurrent Mode with createRoot.

This is based on a real-world scenario arising from certain patterns of usage of react-query (which internally calls Promise.resolve()) and useTransition.

Steps To Reproduce

  1. Open Codesandbox
  2. Click the button
  3. Watch logs in the console

Link to code example: https://codesandbox.io/s/react-state-order-bug-o4izk6?file=/src/App.js:264-265

The current behavior

Console output after button press:

{submitCount: 0, isSubmitScheduled: true}
{submitCount: 1, isSubmitScheduled: true}
{submitCount: 1, isSubmitScheduled: false}

The expected behavior

Console output after button press:

{submitCount: 0, isSubmitScheduled: true}
{submitCount: 0, isSubmitScheduled: false}
{submitCount: 1, isSubmitScheduled: false}

Alternatively, if the updates should have been batched (I'm not sure whether batching should apply here), then the expected output would be):

{submitCount: 0, isSubmitScheduled: true}
{submitCount: 1, isSubmitScheduled: false}

update: now that I've discovered that this applies to microtasks as well, the issue might be related to #24625.

Dremora avatar Jun 01 '22 01:06 Dremora

Interesting. The first state update is marked as DefaultLane because flushPassiveEffects sets the event priority; the second state update is outside that call stack so it reads the priority from window.event, which after a microtask is still the click event, leading to it getting treated as a discrete event and thus SyncLane.

sophiebits avatar Feb 24 '23 07:02 sophiebits

how can we escalate the issue to core react developers?

zuozp8 avatar Mar 29 '23 10:03 zuozp8

The issue is known, there is no need to escalate. We're working on a fix but it's a significant project so it'll take us a while.

gaearon avatar Apr 17 '23 17:04 gaearon

Heloo @Dremora ,

This output {submitCount: 0, isSubmitScheduled: true} {submitCount: 0, isSubmitScheduled: false} {submitCount: 1, isSubmitScheduled: false}

will be generated by creating new useEffect in which we check if isCountUpdateScheduled is true and proceed with the submit count update

**`import React, { useState, useEffect } from "react";

export default function App() { var [submitCount, setSubmitCount] = useState(0); const [isSubmitScheduled, setIsSubmitScheduled] = useState(false); const [isCountUpdateScheduled, setIsCountUpdateScheduled] = useState(false);

const scheduleSubmit = () => setIsSubmitScheduled(true);

useEffect(() => { if (isSubmitScheduled) { setIsSubmitScheduled(false); setIsCountUpdateScheduled(true); } }, [isSubmitScheduled]);

useEffect(() => { if (isCountUpdateScheduled) { setIsCountUpdateScheduled(false); Promise.resolve().then(() => { setSubmitCount((x) => x + 1); }); } }, [isCountUpdateScheduled]);

console.log("render", { submitCount, isSubmitScheduled });

return ( <button type="button" onClick={scheduleSubmit}> Hello ); } `**

darsha1706 avatar Jun 05 '23 16:06 darsha1706

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Apr 10 '24 06:04 github-actions[bot]

bump

Dremora avatar Apr 15 '24 09:04 Dremora

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Jul 14 '24 17:07 github-actions[bot]

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!

github-actions[bot] avatar Jul 21 '24 18:07 github-actions[bot]