Skip to content

Commit b501246

Browse files
committed
Fix infinite loop in legacy mode
In legacy mode we typically commit the suspending fiber and then rerender the nearest boundary to render the fallback in a separate commit. We can't do that when the boundary itself suspends because when we try to do the second pass, it'll suspend again and infinite loop. Interestingly the legacy semantics are not needed in this case because they exist to let an existing partial render fully commit its partial state. In this case there's no partial state, so we can just render the fallback immediately instead.
1 parent 135e5c1 commit b501246

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

packages/react-reconciler/src/ReactFiberThrow.new.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,15 @@ function throwException(
256256
// Note: It doesn't matter whether the component that suspended was
257257
// inside a blocking mode tree. If the Suspense is outside of it, we
258258
// should *not* suspend the commit.
259-
if ((workInProgress.mode & BlockingMode) === NoMode) {
259+
//
260+
// If the suspense boundary suspended itself suspended, we don't have to
261+
// do this trick because nothing was partially started. We can just
262+
// directly do a second pass over the fallback in this render and
263+
// pretend we meant to render that directly.
264+
if (
265+
(workInProgress.mode & BlockingMode) === NoMode &&
266+
workInProgress !== returnFiber
267+
) {
260268
workInProgress.flags |= DidCapture;
261269
sourceFiber.flags |= ForceUpdateForLegacySuspense;
262270

packages/react-reconciler/src/ReactFiberThrow.old.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,15 @@ function throwException(
256256
// Note: It doesn't matter whether the component that suspended was
257257
// inside a blocking mode tree. If the Suspense is outside of it, we
258258
// should *not* suspend the commit.
259-
if ((workInProgress.mode & BlockingMode) === NoMode) {
259+
//
260+
// If the suspense boundary suspended itself suspended, we don't have to
261+
// do this trick because nothing was partially started. We can just
262+
// directly do a second pass over the fallback in this render and
263+
// pretend we meant to render that directly.
264+
if (
265+
(workInProgress.mode & BlockingMode) === NoMode &&
266+
workInProgress !== returnFiber
267+
) {
260268
workInProgress.flags |= DidCapture;
261269
sourceFiber.flags |= ForceUpdateForLegacySuspense;
262270

0 commit comments

Comments
 (0)