From ab8f86b30db84338717dcaa4a57242fb168e89ca Mon Sep 17 00:00:00 2001 From: Janka Uryga Date: Tue, 21 May 2024 22:44:42 +0200 Subject: [PATCH] don't overwrite existing chunk listeners in 'wakeChunkIfInitialized' --- .../react-client/src/ReactFlightClient.js | 20 ++++++- .../__tests__/ReactFlightDOMBrowser-test.js | 52 +++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 6e4d28c5e907d..86e2954782cef 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -320,8 +320,24 @@ function wakeChunkIfInitialized( case PENDING: case BLOCKED: case CYCLIC: - chunk.value = resolveListeners; - chunk.reason = rejectListeners; + if (chunk.value) { + for (let i = 0; i < resolveListeners.length; i++) { + chunk.value.push(resolveListeners[i]); + } + } else { + chunk.value = resolveListeners; + } + + if (chunk.reason) { + if (rejectListeners) { + for (let i = 0; i < rejectListeners.length; i++) { + chunk.reason.push(rejectListeners[i]); + } + } + } else { + chunk.reason = rejectListeners; + } + break; case ERRORED: if (rejectListeners) { diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index e9bdc4b6db33d..040fd1b59c144 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -296,6 +296,58 @@ describe('ReactFlightDOMBrowser', () => { expect(container.innerHTML).toBe('
[[1,2,3],[1,2,3]]
'); }); + it('should resolve deduped objects within the same model root when it is blocked and there is a listener attached to the root', async () => { + let resolveClientComponentChunk; + + const ClientOuter = clientExports(function ClientOuter({Component, value}) { + return ; + }); + + const ClientInner = clientExports( + function ClientInner({value}) { + return
{JSON.stringify(value)}
; + }, + '42', + '/test.js', + new Promise(resolve => (resolveClientComponentChunk = resolve)), + ); + + function Server({value}) { + return ; + } + + const shared = [1, 2, 3]; + const value = [shared, shared]; + + const stream = ReactServerDOMServer.renderToReadableStream( + , + webpackMap, + ); + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromReadableStream(stream); + // make sure we have a listener so that `resolveModelChunk` initializes the chunk eagerly + response.then(() => {}); + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(); + }); + + expect(container.innerHTML).toBe(''); + + await act(() => { + resolveClientComponentChunk(); + }); + + expect(container.innerHTML).toBe('
[[1,2,3],[1,2,3]]
'); + }); + it('should progressively reveal server components', async () => { let reportedErrors = [];