diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index d9b604c17507..b988bd72caff 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -10832,4 +10832,56 @@ Unfortunately that previous paragraph wasn't quite long enough so I'll continue , ); }); + + 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 ( + + + + }> + hello world + + + + + + + + ); + } + + await act(async () => { + const {pipe} = renderToPipeableStream(, { + onError() {}, + }); + pipe(writable); + }); + + await act(() => { + resolve('!'); + }); + + expect(getVisibleChildren(document)).toEqual( + + + + hello world + ! + + , + ); + }); }); diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index b8184a198370..07408d64e881 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -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, @@ -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. @@ -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; }