Skip to content

Commit b74a718

Browse files
committed
Always outline object keys in Map/Set
This won't always work but it'll work if we discover the Map/Set before the key. The idea is that you'd pass the Map to something like a parent context and then select out of it with a key passed to a child.
1 parent 19504e7 commit b74a718

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

packages/react-client/src/__tests__/ReactFlight-test.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,13 @@ describe('ReactFlight', () => {
374374
});
375375

376376
it('can transport Map', async () => {
377-
function ComponentClient({prop}) {
377+
function ComponentClient({prop, selected}) {
378378
return `
379379
map: ${prop instanceof Map}
380380
size: ${prop.size}
381381
greet: ${prop.get('hi').greet}
382382
content: ${JSON.stringify(Array.from(prop))}
383+
selected: ${prop.get(selected)}
383384
`;
384385
}
385386
const Component = clientReference(ComponentClient);
@@ -389,7 +390,7 @@ describe('ReactFlight', () => {
389390
['hi', {greet: 'world'}],
390391
[objKey, 123],
391392
]);
392-
const model = <Component prop={map} />;
393+
const model = <Component prop={map} selected={objKey} />;
393394

394395
const transport = ReactNoopFlightServer.render(model);
395396

@@ -402,23 +403,25 @@ describe('ReactFlight', () => {
402403
size: 2
403404
greet: world
404405
content: [["hi",{"greet":"world"}],[{"obj":"key"},123]]
406+
selected: 123
405407
`);
406408
});
407409

408410
it('can transport Set', async () => {
409-
function ComponentClient({prop}) {
411+
function ComponentClient({prop, selected}) {
410412
return `
411413
set: ${prop instanceof Set}
412414
size: ${prop.size}
413415
hi: ${prop.has('hi')}
414416
content: ${JSON.stringify(Array.from(prop))}
417+
selected: ${prop.has(selected)}
415418
`;
416419
}
417420
const Component = clientReference(ComponentClient);
418421

419422
const objKey = {obj: 'key'};
420423
const set = new Set(['hi', objKey]);
421-
const model = <Component prop={set} />;
424+
const model = <Component prop={set} selected={objKey} />;
422425

423426
const transport = ReactNoopFlightServer.render(model);
424427

@@ -431,6 +434,7 @@ describe('ReactFlight', () => {
431434
size: 2
432435
hi: true
433436
content: ["hi",{"obj":"key"}]
437+
selected: true
434438
`);
435439
});
436440

packages/react-server/src/ReactFlightServer.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -822,12 +822,36 @@ function serializeMap(
822822
request: Request,
823823
map: Map<ReactClientValue, ReactClientValue>,
824824
): string {
825-
const id = outlineModel(request, Array.from(map));
825+
const entries = Array.from(map);
826+
for (let i = 0; i < entries.length; i++) {
827+
const key = entries[i][0];
828+
if (typeof key === 'object' && key !== null) {
829+
const writtenObjects = request.writtenObjects;
830+
const existingId = writtenObjects.get(key);
831+
if (existingId === undefined) {
832+
// Mark all object keys as seen so that they're always outlined.
833+
writtenObjects.set(key, -1);
834+
}
835+
}
836+
}
837+
const id = outlineModel(request, entries);
826838
return '$Q' + id.toString(16);
827839
}
828840

829841
function serializeSet(request: Request, set: Set<ReactClientValue>): string {
830-
const id = outlineModel(request, Array.from(set));
842+
const entries = Array.from(set);
843+
for (let i = 0; i < entries.length; i++) {
844+
const key = entries[i];
845+
if (typeof key === 'object' && key !== null) {
846+
const writtenObjects = request.writtenObjects;
847+
const existingId = writtenObjects.get(key);
848+
if (existingId === undefined) {
849+
// Mark all object keys as seen so that they're always outlined.
850+
writtenObjects.set(key, -1);
851+
}
852+
}
853+
}
854+
const id = outlineModel(request, entries);
831855
return '$W' + id.toString(16);
832856
}
833857

0 commit comments

Comments
 (0)