react icon indicating copy to clipboard operation
react copied to clipboard

Bug: useSyncExternalStore update not batched within unstable_batchedUpdates

Open Andarist opened this issue 3 years ago • 2 comments

Steps To Reproduce

  1. schedule two updates using "default priority" scope (eg. from within setTimeout)
  2. let one of the updates be handled through useSyncExternalStore and let the other one be handled through regular setState

Link to code example: https://codesandbox.io/s/interesting-chatterjee-9ed8hj?file=/src/App.js (without unstable_batchedUpdates) https://codesandbox.io/s/prod-glitter-51vwm1?file=/src/App.js (with unstable_batchedUpdates)

The current behavior

The useSyncExternalStore update gets flushed and committed before the other one has a chance to be committed to the screen. This doesn't allow me to read the updated state of the committed DOM of the children components from within the Parent's effect

The expected behavior

I would expect to be able to "join" this sync update of the useSyncExternalStore somehow. Ideally, I wouldn't have to wrap both with unstable_batchedUpdates. It would be cool if I could just schedule a single update with the same priority. If I understand correctly multiple updates coming from different useSyncExternalStore updates can be batched together (it doesn't work like flushSync, so it doesn't literally immediately flush the scheduled update) - and I would just like to hop on that train with my second update.

I could live with the solution based on unstable_batchedUpdates but that doesn't seem to work either.

Andarist avatar Jun 30 '22 17:06 Andarist

Andarist pointed out this is likely the cause of https://github.com/reduxjs/react-redux/issues/1912

markerikson avatar Aug 14 '22 17:08 markerikson

unstable_batchedUpdates is a way to deprioritize an update by delaying it. The default priority is even more delayed and more batched than unstable_batchedUpdates. So unstable_batchedUpdates is a noop in React 18.

If you need the consistency you need to compromise - by making your updates less batched and flush earlier than they otherwise would - using flushSync.

That's the compromise of using useSyncExternalStore. To preserve consistency with external mutable store you have to make it less batchable - less delayed, than other forms of updates.

sebmarkbage avatar Sep 05 '22 21:09 sebmarkbage

So unstable_batchedUpdates is a noop in React 18.

Cool, that's the first time I'm seeing this. Is the same true for unstable_batchedUpdates from react-native @sebmarkbage ?

TkDodo avatar Oct 31 '22 11:10 TkDodo

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 04:04 github-actions[bot]

bump

TkDodo avatar Apr 10 '24 07:04 TkDodo

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 09 '24 23:07 github-actions[bot]

BUMP!

markerikson avatar Jul 09 '24 23:07 markerikson

This is fixed in the RC and has been fixed in canary for awhile. We now flush default with all other sync updates.

Screenshot 2024-07-12 at 11 49 36 PM

https://codesandbox.io/s/stupefied-julien-6fysc9?file=/package.json

If I'm missing something let me know and I'll re-open.

rickhanlonii avatar Jul 13 '24 03:07 rickhanlonii