failing test demonstrating infinite updates #25179
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This was.... fun?
So in a Next.js project there was an infinite updates issue causing a page to fail and unmount. After narrowing the scope of the problem as much as possible I was able to start to repro in a test case (see ReactDOMHooks-test.js)
There is a confluence of things happening
In StrictMode some effects are refired
In a SuspenseBoundary there is a OffscreenComponent fiber as a child fiber
DoubleInvoke-ing effects in Dev looks for whether there is a PlacementDEV flag or (critically) if the fiber is an OffscreenComponent.
This means that for every descendant of a SuspenseBoundary, you will double-invoke effects even on updates that happened after a Placement (In StrictMode of course)
So what is happening in this contrived test case is
a first layoutEffect is causing an immediate Sync render. there is also a passive effect queued to some non Sync lane.
a second layoutEffect is causing another immediate Sync render however b/c the passive effect is inside an OffscreenComponent it gets cleanedup and re-executed.
This effect has a setState but it cannot bail out of the update because there is pending work already on this fiber (from a previous run of the effect). It takes a few loops around but eventually there is an inifinite loop of setStates causing Sync renders causing setStates that cannot be bailed out, causing Sync renders...
At least I think...
The simple fix is probably to not always doubleinvoke with an OffscreenComponent child. I think that is wrong in the SuspenseBoundary case but maybe it makes sense for regular offscreen. I don't really know though