Skip to content

Commit 9c2a8dd

Browse files
authored
[Flight] Ensure we dedupe references if we later discover that it's the model root (#33666)
I noticed we weren't deduping these cases.
1 parent 811e203 commit 9c2a8dd

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,4 +2574,54 @@ describe('ReactFlightDOMBrowser', () => {
25742574
expect(errors).toEqual([new Error('Connection closed.')]);
25752575
expect(container.innerHTML).toBe('');
25762576
});
2577+
2578+
it('can dedupe references inside promises', async () => {
2579+
const foo = {};
2580+
const bar = {
2581+
foo: foo,
2582+
};
2583+
foo.bar = bar;
2584+
2585+
const object = {
2586+
foo: Promise.resolve(foo),
2587+
bar: Promise.resolve(bar),
2588+
};
2589+
2590+
const stream = await serverAct(() =>
2591+
ReactServerDOMServer.renderToReadableStream(object, webpackMap),
2592+
);
2593+
2594+
const response = await ReactServerDOMClient.createFromReadableStream(
2595+
passThrough(stream),
2596+
);
2597+
2598+
const responseFoo = await response.foo;
2599+
const responseBar = await response.bar;
2600+
expect(responseFoo.bar).toBe(responseBar);
2601+
expect(responseBar.foo).toBe(responseFoo);
2602+
});
2603+
2604+
it('can deduped outlined references inside promises', async () => {
2605+
const foo = {};
2606+
const bar = new Set([foo]); // This will be outlined which can create a future reference
2607+
foo.bar = bar;
2608+
2609+
const object = {
2610+
foo: Promise.resolve(foo),
2611+
bar: Promise.resolve(bar),
2612+
};
2613+
2614+
const stream = await serverAct(() =>
2615+
ReactServerDOMServer.renderToReadableStream(object, webpackMap),
2616+
);
2617+
2618+
const response = await ReactServerDOMClient.createFromReadableStream(
2619+
passThrough(stream),
2620+
);
2621+
2622+
const responseFoo = await response.foo;
2623+
const responseBar = await response.bar;
2624+
expect(responseFoo.bar).toBe(responseBar);
2625+
expect(Array.from(responseBar)[0]).toBe(responseFoo);
2626+
});
25772627
});

packages/react-server/src/ReactFlightServer.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3220,6 +3220,11 @@ function renderModelDestructive(
32203220

32213221
if (existingReference !== undefined) {
32223222
if (modelRoot === value) {
3223+
if (existingReference !== serializeByValueID(task.id)) {
3224+
// Turns out that we already have this root at a different reference.
3225+
// Use that after all.
3226+
return existingReference;
3227+
}
32233228
// This is the ID we're currently emitting so we need to write it
32243229
// once but if we discover it again, we refer to it by id.
32253230
modelRoot = null;

0 commit comments

Comments
 (0)