Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10832,4 +10832,56 @@ Unfortunately that previous paragraph wasn't quite long enough so I'll continue
</html>,
);
});

it('not error when a suspended fallback segment directly inside another Suspense is abandoned', async () => {
function SuspendForever() {
React.use(new Promise(() => {}));
}

let resolve = () => {};
const suspendPromise = new Promise(r => {
resolve = r;
});
function Suspend() {
return React.use(suspendPromise);
}

function App() {
return (
<html>
<body>
<Suspense fallback="outer">
<Suspense fallback={<SuspendForever />}>
<span>hello world</span>
<span>
<Suspend />
</span>
</Suspense>
</Suspense>
</body>
</html>
);
}

await act(async () => {
const {pipe} = renderToPipeableStream(<App />, {
onError() {},
});
pipe(writable);
});

await act(() => {
resolve('!');
});

expect(getVisibleChildren(document)).toEqual(
<html>
<head />
<body>
<span>hello world</span>
<span>!</span>
</body>
</html>,
);
});
});
8 changes: 6 additions & 2 deletions packages/react-server/src/ReactFizzServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ type Segment = {
// The context that this segment was created in.
parentFormatContext: FormatContext,
// If this segment represents a fallback, this is the content that will replace that fallback.
+boundary: null | SuspenseBoundary,
boundary: null | SuspenseBoundary,
// used to discern when text separator boundaries are needed
lastPushedText: boolean,
textEmbedded: boolean,
Expand Down Expand Up @@ -5681,6 +5681,10 @@ function flushSegment(
return flushSubtree(request, destination, segment, hoistableState);
}

// We're going to write the boundary. We don't need to maintain this reference since
// we might reflush this segment at a later time (if it aborts and we inlined) but
// we don't want to reflush the boundary
segment.boundary = null;
boundary.parentFlushed = true;
// This segment is a Suspense boundary. We need to decide whether to
// emit the content or the fallback now.
Expand Down Expand Up @@ -5952,7 +5956,7 @@ function flushPartiallyCompletedSegment(
segment: Segment,
): boolean {
if (segment.status === FLUSHED) {
// We've already flushed this inline.
// We've already flushed this inline
return true;
}

Expand Down
Loading