Skip to content

Commit

Permalink
Fix infinite loop in legacy mode
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sebmarkbage committed Dec 1, 2020
1 parent 135e5c1 commit 32e2604
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 2 deletions.
10 changes: 9 additions & 1 deletion packages/react-reconciler/src/ReactFiberThrow.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,15 @@ function throwException(
// Note: It doesn't matter whether the component that suspended was
// inside a blocking mode tree. If the Suspense is outside of it, we
// should *not* suspend the commit.
if ((workInProgress.mode & BlockingMode) === NoMode) {
//
// If the suspense boundary suspended itself suspended, we don't have to
// do this trick because nothing was partially started. We can just
// directly do a second pass over the fallback in this render and
// pretend we meant to render that directly.
if (
(workInProgress.mode & BlockingMode) === NoMode &&
workInProgress !== returnFiber
) {
workInProgress.flags |= DidCapture;
sourceFiber.flags |= ForceUpdateForLegacySuspense;

Expand Down
9 changes: 8 additions & 1 deletion packages/react-reconciler/src/ReactFiberThrow.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,14 @@ function throwException(
// Note: It doesn't matter whether the component that suspended was
// inside a blocking mode tree. If the Suspense is outside of it, we
// should *not* suspend the commit.
if ((workInProgress.mode & BlockingMode) === NoMode) {
//
// If the suspense boundary suspended itself suspended, we don't have to
// do this trick because nothing was partially started. We can just
// directly do a second pass over the fallback in this render.
if (
(workInProgress.mode & BlockingMode) === NoMode &&
workInProgress !== returnFiber
) {
workInProgress.flags |= DidCapture;
sourceFiber.flags |= ForceUpdateForLegacySuspense;

Expand Down

0 comments on commit 32e2604

Please sign in to comment.