dillon1000/react

Commit

[Bugfix] Prevent infinite update loop caused by a synchronous update in a passive effect (#22277)

* Add test that triggers infinite update loop

In 18, passive effects are flushed synchronously if they are the
result of a synchronous update. We have a guard for infinite update
loops that occur in the layout phase, but it doesn't currently work for
synchronous updates from a passive effect.

The reason this probably hasn't come up yet is because synchronous
updates inside the passive effect phase are relatively rare: you either
have to imperatively dispatch a discrete event, like `el.focus`, or you
have to call `ReactDOM.flushSync`, which triggers a warning. (In
general, updates inside a passive effect are not encouraged.)

I discovered this because `useSyncExternalStore` does sometimes
trigger updates inside the passive effect phase.

This commit adds a failing test to prove the issue exists. I will fix
it in the next commit.

* Fix failing test added in previous commit

The way we detect a "nested update" is if there's synchronous work
remaining at the end of the commit phase.

Currently this check happens before we synchronously flush the passive
effects. I moved it to after the effects are fired, so that it detects
whether synchronous work was scheduled in that phase.
Browse files
Changed paths3 files
First-parent comparison
M packages/react-dom/src/__tests__/ReactUpdates-test.js ModifiedM packages/react-reconciler/src/ReactFiberWorkLoop.new.js ModifiedM packages/react-reconciler/src/ReactFiberWorkLoop.old.js Modified
Patch

Files changed

Rendering syntax-highlighted changes…