Skip to content

Commit 06f4858

Browse files
committed
Defer execution of the main content of a deferred Suspense Boundary
This is similar to what we do with prerenders.
1 parent 37023dd commit 06f4858

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10886,11 +10886,16 @@ Unfortunately that previous paragraph wasn't quite long enough so I'll continue
1088610886
});
1088710887

1088810888
it('outlines deferred Suspense boundaries', async () => {
10889+
function Log({text}) {
10890+
Scheduler.log(text);
10891+
return text;
10892+
}
10893+
1088910894
await act(async () => {
1089010895
renderToPipeableStream(
1089110896
<div>
10892-
<Suspense defer={true} fallback="Waiting">
10893-
<span>hello</span>
10897+
<Suspense defer={true} fallback={<Log text="Waiting" />}>
10898+
<span>{<Log text="hello" />}</span>
1089410899
</Suspense>
1089510900
</div>,
1089610901
).pipe(writable);
@@ -10900,6 +10905,8 @@ Unfortunately that previous paragraph wasn't quite long enough so I'll continue
1090010905
expect(getVisibleChildren(temp)).toEqual(<div>Waiting</div>);
1090110906
});
1090210907

10908+
assertLog(['Waiting', 'hello']);
10909+
1090310910
expect(getVisibleChildren(container)).toEqual(
1090410911
<div>
1090510912
<span>hello</span>

packages/react-server/src/ReactFizzServer.js

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,29 +1377,32 @@ function renderSuspenseBoundary(
13771377
// no parent segment so there's nothing to wait on.
13781378
contentRootSegment.parentFlushed = true;
13791379

1380-
if (request.trackedPostpones !== null) {
1380+
const trackedPostpones = request.trackedPostpones;
1381+
if (trackedPostpones !== null || defer) {
1382+
// This is a prerender or deferred boundary. In this mode we want to render the fallback synchronously
1383+
// and schedule the content to render later. This is the opposite of what we do during a normal render
1384+
// where we try to skip rendering the fallback if the content itself can render synchronously
1385+
13811386
// Stash the original stack frame.
13821387
const suspenseComponentStack = task.componentStack;
1383-
// This is a prerender. In this mode we want to render the fallback synchronously and schedule
1384-
// the content to render later. This is the opposite of what we do during a normal render
1385-
// where we try to skip rendering the fallback if the content itself can render synchronously
1386-
const trackedPostpones = request.trackedPostpones;
13871388

13881389
const fallbackKeyPath: KeyNode = [
13891390
keyPath[0],
13901391
'Suspense Fallback',
13911392
keyPath[2],
13921393
];
1393-
const fallbackReplayNode: ReplayNode = [
1394-
fallbackKeyPath[1],
1395-
fallbackKeyPath[2],
1396-
([]: Array<ReplayNode>),
1397-
null,
1398-
];
1399-
trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
1400-
// We are rendering the fallback before the boundary content so we keep track of
1401-
// the fallback replay node until we determine if the primary content suspends
1402-
newBoundary.trackedFallbackNode = fallbackReplayNode;
1394+
if (trackedPostpones !== null) {
1395+
const fallbackReplayNode: ReplayNode = [
1396+
fallbackKeyPath[1],
1397+
fallbackKeyPath[2],
1398+
([]: Array<ReplayNode>),
1399+
null,
1400+
];
1401+
trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
1402+
// We are rendering the fallback before the boundary content so we keep track of
1403+
// the fallback replay node until we determine if the primary content suspends
1404+
newBoundary.trackedFallbackNode = fallbackReplayNode;
1405+
}
14031406

14041407
task.blockedSegment = boundarySegment;
14051408
task.blockedPreamble = newBoundary.fallbackPreamble;

0 commit comments

Comments
 (0)