Skip to content

Commit 7d5ad2e

Browse files
committed
Never outline element props in Flight Server
This avoids having to handle stale blocked elements (with `null` props) in the Flight Client.
1 parent c578cff commit 7d5ad2e

File tree

2 files changed

+17
-25
lines changed

2 files changed

+17
-25
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -585,18 +585,6 @@ function createModelResolver<T>(
585585
return value => {
586586
parentObject[key] = value;
587587

588-
// If this is a tuple that's representing a react element, and the props
589-
// were resolved (4th item, key '3'), the props of `blocked.value` must be
590-
// updated.
591-
if (
592-
Array.isArray(parentObject) &&
593-
key === '3' &&
594-
blocked.value &&
595-
blocked.value.$$typeof === REACT_ELEMENT_TYPE
596-
) {
597-
blocked.value.props = value;
598-
}
599-
600588
// If this is the root object for a model reference, where `blocked.value`
601589
// is a stale `null`, the resolved value can be used directly.
602590
if (key === '' && blocked.value === null) {

packages/react-server/src/ReactFlightServer.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,16 @@ export type ReactClientValue =
243243

244244
type ReactClientObject = {+[key: string]: ReactClientValue};
245245

246+
// task status
246247
const PENDING = 0;
247248
const COMPLETED = 1;
248249
const ABORTED = 3;
249250
const ERRORED = 4;
250251

252+
// object reference status
253+
const SEEN_BUT_NOT_YET_OUTLINED = -1;
254+
const NEVER_OUTLINED = -2;
255+
251256
type Task = {
252257
id: number,
253258
status: 0 | 1 | 3 | 4,
@@ -280,7 +285,7 @@ export type Request = {
280285
writtenSymbols: Map<symbol, number>,
281286
writtenClientReferences: Map<ClientReferenceKey, number>,
282287
writtenServerReferences: Map<ServerReference<any>, number>,
283-
writtenObjects: WeakMap<Reference, number>, // -1 means "seen" but not outlined.
288+
writtenObjects: WeakMap<Reference, number>,
284289
identifierPrefix: string,
285290
identifierCount: number,
286291
taintCleanupQueue: Array<string | bigint>,
@@ -1125,8 +1130,7 @@ function serializeMap(
11251130
const writtenObjects = request.writtenObjects;
11261131
const existingId = writtenObjects.get(key);
11271132
if (existingId === undefined) {
1128-
// Mark all object keys as seen so that they're always outlined.
1129-
writtenObjects.set(key, -1);
1133+
writtenObjects.set(key, SEEN_BUT_NOT_YET_OUTLINED);
11301134
}
11311135
}
11321136
}
@@ -1142,8 +1146,7 @@ function serializeSet(request: Request, set: Set<ReactClientValue>): string {
11421146
const writtenObjects = request.writtenObjects;
11431147
const existingId = writtenObjects.get(key);
11441148
if (existingId === undefined) {
1145-
// Mark all object keys as seen so that they're always outlined.
1146-
writtenObjects.set(key, -1);
1149+
writtenObjects.set(key, SEEN_BUT_NOT_YET_OUTLINED);
11471150
}
11481151
}
11491152
}
@@ -1328,8 +1331,7 @@ function renderModelDestructive(
13281331
// This is the ID we're currently emitting so we need to write it
13291332
// once but if we discover it again, we refer to it by id.
13301333
modelRoot = null;
1331-
} else if (existingId === -1) {
1332-
// Seen but not yet outlined.
1334+
} else if (existingId === SEEN_BUT_NOT_YET_OUTLINED) {
13331335
// TODO: If we throw here we can treat this as suspending which causes an outline
13341336
// but that is able to reuse the same task if we're already in one but then that
13351337
// will be a lazy future value rather than guaranteed to exist but maybe that's good.
@@ -1348,7 +1350,10 @@ function renderModelDestructive(
13481350
} else {
13491351
// This is the first time we've seen this object. We may never see it again
13501352
// so we'll inline it. Mark it as seen. If we see it again, we'll outline.
1351-
writtenObjects.set(value, -1);
1353+
writtenObjects.set(value, SEEN_BUT_NOT_YET_OUTLINED);
1354+
// The element's props are marked as "never outlined" so that they are inlined into
1355+
// the same row as the element itself.
1356+
writtenObjects.set(value.props, NEVER_OUTLINED);
13521357
}
13531358

13541359
const element: React$Element<any> = (value: any);
@@ -1477,19 +1482,18 @@ function renderModelDestructive(
14771482
// This is the ID we're currently emitting so we need to write it
14781483
// once but if we discover it again, we refer to it by id.
14791484
modelRoot = null;
1480-
} else if (existingId === -1) {
1481-
// Seen but not yet outlined.
1485+
} else if (existingId === SEEN_BUT_NOT_YET_OUTLINED) {
14821486
const newId = outlineModel(request, (value: any));
14831487
return serializeByValueID(newId);
1484-
} else {
1488+
} else if (existingId !== NEVER_OUTLINED) {
14851489
// We've already emitted this as an outlined object, so we can
14861490
// just refer to that by its existing ID.
14871491
return serializeByValueID(existingId);
14881492
}
14891493
} else {
14901494
// This is the first time we've seen this object. We may never see it again
14911495
// so we'll inline it. Mark it as seen. If we see it again, we'll outline.
1492-
writtenObjects.set(value, -1);
1496+
writtenObjects.set(value, SEEN_BUT_NOT_YET_OUTLINED);
14931497
}
14941498

14951499
if (isArray(value)) {
@@ -2007,7 +2011,7 @@ function renderConsoleValue(
20072011
return serializeInfinitePromise();
20082012
}
20092013

2010-
if (existingId !== undefined && existingId !== -1) {
2014+
if (existingId !== undefined && existingId >= 0) {
20112015
// We've already emitted this as a real object, so we can
20122016
// just refer to that by its existing ID.
20132017
return serializeByValueID(existingId);

0 commit comments

Comments
 (0)