diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js
index a6ee56a09061e..a207b5e9ef05c 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.js
@@ -2355,18 +2355,20 @@ function initSuspenseListRenderState(
tail: null | Fiber,
lastContentRow: null | Fiber,
tailMode: SuspenseListTailMode,
+ lastEffectBeforeRendering: null | Fiber,
): void {
let renderState: null | SuspenseListRenderState =
workInProgress.memoizedState;
if (renderState === null) {
- workInProgress.memoizedState = {
+ workInProgress.memoizedState = ({
isBackwards: isBackwards,
rendering: null,
last: lastContentRow,
tail: tail,
tailExpiration: 0,
tailMode: tailMode,
- };
+ lastEffect: lastEffectBeforeRendering,
+ }: SuspenseListRenderState);
} else {
// We can reuse the existing object from previous renders.
renderState.isBackwards = isBackwards;
@@ -2375,6 +2377,7 @@ function initSuspenseListRenderState(
renderState.tail = tail;
renderState.tailExpiration = 0;
renderState.tailMode = tailMode;
+ renderState.lastEffect = lastEffectBeforeRendering;
}
}
@@ -2456,6 +2459,7 @@ function updateSuspenseListComponent(
tail,
lastContentRow,
tailMode,
+ workInProgress.lastEffect,
);
break;
}
@@ -2487,6 +2491,7 @@ function updateSuspenseListComponent(
tail,
null, // last
tailMode,
+ workInProgress.lastEffect,
);
break;
}
@@ -2497,6 +2502,7 @@ function updateSuspenseListComponent(
null, // tail
null, // last
undefined,
+ workInProgress.lastEffect,
);
break;
}
diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js
index 2436ec6af6a63..8bb417723fdfc 100644
--- a/packages/react-reconciler/src/ReactFiberCompleteWork.js
+++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js
@@ -1053,7 +1053,10 @@ function completeWork(
// Rerender the whole list, but this time, we'll force fallbacks
// to stay in place.
// Reset the effect list before doing the second pass since that's now invalid.
- workInProgress.firstEffect = workInProgress.lastEffect = null;
+ if (renderState.lastEffect === null) {
+ workInProgress.firstEffect = null;
+ }
+ workInProgress.lastEffect = renderState.lastEffect;
// Reset the child fibers to their original state.
resetChildFibers(workInProgress, renderExpirationTime);
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js
index e22dc8ccd63cb..f41e7a5073eed 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js
@@ -585,6 +585,90 @@ describe('ReactSuspenseList', () => {
);
});
+ it('displays all "together" during an update', async () => {
+ let A = createAsyncText('A');
+ let B = createAsyncText('B');
+ let C = createAsyncText('C');
+ let D = createAsyncText('D');
+
+ function Foo({step}) {
+ return (
+
+ {step === 0 && (
+ }>
+
+
+ )}
+ {step === 0 && (
+ }>
+
+
+ )}
+ {step === 1 && (
+ }>
+
+
+ )}
+ {step === 1 && (
+ }>
+
+
+ )}
+
+ );
+ }
+
+ // Mount
+ await A.resolve();
+ ReactNoop.render();
+ expect(Scheduler).toFlushAndYield([
+ 'A',
+ 'Suspend! [B]',
+ 'Loading B',
+ 'Loading A',
+ 'Loading B',
+ ]);
+ expect(ReactNoop).toMatchRenderedOutput(
+ <>
+ Loading A
+ Loading B
+ >,
+ );
+ await B.resolve();
+ expect(Scheduler).toFlushAndYield(['A', 'B']);
+ expect(ReactNoop).toMatchRenderedOutput(
+ <>
+ A
+ B
+ >,
+ );
+
+ // Update
+ await C.resolve();
+ ReactNoop.render();
+ expect(Scheduler).toFlushAndYield([
+ 'C',
+ 'Suspend! [D]',
+ 'Loading D',
+ 'Loading C',
+ 'Loading D',
+ ]);
+ expect(ReactNoop).toMatchRenderedOutput(
+ <>
+ Loading C
+ Loading D
+ >,
+ );
+ await D.resolve();
+ expect(Scheduler).toFlushAndYield(['C', 'D']);
+ expect(ReactNoop).toMatchRenderedOutput(
+ <>
+ C
+ D
+ >,
+ );
+ });
+
it('avoided boundaries can be coordinate with SuspenseList', async () => {
let A = createAsyncText('A');
let B = createAsyncText('B');