Skip to content

Commit 6686619

Browse files
committed
Add approximate parent context for FormatContext
1 parent e233218 commit 6686619

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

packages/react-dom-bindings/src/server/ReactFlightServerConfigDOM.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,17 @@ export type Hints = Set<string>;
6161
export function createHints(): Hints {
6262
return new Set();
6363
}
64+
65+
export opaque type FormatContext = null;
66+
67+
export function createRootFormatContext(): FormatContext {
68+
return null;
69+
}
70+
71+
export function getChildFormatContext(
72+
parentContext: FormatContext,
73+
type: string,
74+
props: Object,
75+
): FormatContext {
76+
return parentContext;
77+
}

packages/react-server/src/ReactFlightServer.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import type {
4949
Hints,
5050
HintCode,
5151
HintModel,
52+
FormatContext,
5253
} from './ReactFlightServerConfig';
5354
import type {ThenableState} from './ReactFlightThenable';
5455
import type {
@@ -88,6 +89,8 @@ import {
8889
supportsRequestStorage,
8990
requestStorage,
9091
createHints,
92+
createRootFormatContext,
93+
getChildFormatContext,
9194
initAsyncDebugInfo,
9295
markAsyncSequenceRootTask,
9396
getCurrentAsyncSequence,
@@ -525,6 +528,7 @@ type Task = {
525528
toJSON: (key: string, value: ReactClientValue) => ReactJSONValue,
526529
keyPath: null | string, // parent server component keys
527530
implicitSlot: boolean, // true if the root server component of this sequence had a null key
531+
formatContext: FormatContext, // an approximate parent context from host components
528532
thenableState: ThenableState | null,
529533
timed: boolean, // Profiling-only. Whether we need to track the completion time of this task.
530534
time: number, // Profiling-only. The last time stamp emitted for this task.
@@ -758,6 +762,7 @@ function RequestInstance(
758762
model,
759763
null,
760764
false,
765+
createRootFormatContext(),
761766
abortSet,
762767
timeOrigin,
763768
null,
@@ -980,6 +985,7 @@ function serializeThenable(
980985
(thenable: any), // will be replaced by the value before we retry. used for debug info.
981986
task.keyPath, // the server component sequence continues through Promise-as-a-child.
982987
task.implicitSlot,
988+
task.formatContext,
983989
request.abortableTasks,
984990
enableProfilerTimer &&
985991
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -1102,6 +1108,7 @@ function serializeReadableStream(
11021108
task.model,
11031109
task.keyPath,
11041110
task.implicitSlot,
1111+
task.formatContext,
11051112
request.abortableTasks,
11061113
enableProfilerTimer &&
11071114
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -1197,6 +1204,7 @@ function serializeAsyncIterable(
11971204
task.model,
11981205
task.keyPath,
11991206
task.implicitSlot,
1207+
task.formatContext,
12001208
request.abortableTasks,
12011209
enableProfilerTimer &&
12021210
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -2028,6 +2036,7 @@ function deferTask(request: Request, task: Task): ReactJSONValue {
20282036
task.model, // the currently rendering element
20292037
task.keyPath, // unlike outlineModel this one carries along context
20302038
task.implicitSlot,
2039+
task.formatContext,
20312040
request.abortableTasks,
20322041
enableProfilerTimer &&
20332042
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -2048,6 +2057,7 @@ function outlineTask(request: Request, task: Task): ReactJSONValue {
20482057
task.model, // the currently rendering element
20492058
task.keyPath, // unlike outlineModel this one carries along context
20502059
task.implicitSlot,
2060+
task.formatContext,
20512061
request.abortableTasks,
20522062
enableProfilerTimer &&
20532063
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -2214,6 +2224,22 @@ function renderElement(
22142224
}
22152225
}
22162226
}
2227+
} else if (typeof type === 'string') {
2228+
const parentFormatContext = task.formatContext;
2229+
const newFormatContext = getChildFormatContext(
2230+
parentFormatContext,
2231+
type,
2232+
props,
2233+
);
2234+
if (parentFormatContext !== newFormatContext && props.children != null) {
2235+
// We've entered a new context. We need to create another Task which has
2236+
// the new context set up since it's not safe to push/pop in the middle of
2237+
// a tree. Additionally this means that any deduping within this tree now
2238+
// assumes the new context even if it's reused outside in a different context.
2239+
// We'll rely on this to dedupe the value later as we discover it again
2240+
// inside the returned element's tree.
2241+
outlineModelWithFormatContext(request, props.children, newFormatContext);
2242+
}
22172243
}
22182244
// For anything else, try it on the client instead.
22192245
// We don't know if the client will support it or not. This might error on the
@@ -2530,6 +2556,7 @@ function createTask(
25302556
model: ReactClientValue,
25312557
keyPath: null | string,
25322558
implicitSlot: boolean,
2559+
formatContext: FormatContext,
25332560
abortSet: Set<Task>,
25342561
lastTimestamp: number, // Profiling-only
25352562
debugOwner: null | ReactComponentInfo, // DEV-only
@@ -2554,6 +2581,7 @@ function createTask(
25542581
model,
25552582
keyPath,
25562583
implicitSlot,
2584+
formatContext: formatContext,
25572585
ping: () => pingTask(request, task),
25582586
toJSON: function (
25592587
this:
@@ -2819,11 +2847,26 @@ function serializeDebugClientReference(
28192847
}
28202848

28212849
function outlineModel(request: Request, value: ReactClientValue): number {
2850+
return outlineModelWithFormatContext(
2851+
request,
2852+
value,
2853+
// For deduped values we don't know which context it will be reused in
2854+
// so we have to assume that it's the root context.
2855+
createRootFormatContext(),
2856+
);
2857+
}
2858+
2859+
function outlineModelWithFormatContext(
2860+
request: Request,
2861+
value: ReactClientValue,
2862+
formatContext: FormatContext,
2863+
): number {
28222864
const newTask = createTask(
28232865
request,
28242866
value,
28252867
null, // The way we use outlining is for reusing an object.
28262868
false, // It makes no sense for that use case to be contextual.
2869+
formatContext, // Except for FormatContext we optimistically use it.
28272870
request.abortableTasks,
28282871
enableProfilerTimer &&
28292872
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -3071,6 +3114,7 @@ function serializeBlob(request: Request, blob: Blob): string {
30713114
model,
30723115
null,
30733116
false,
3117+
createRootFormatContext(),
30743118
request.abortableTasks,
30753119
enableProfilerTimer &&
30763120
(enableComponentPerformanceTrack || enableAsyncDebugInfo)
@@ -3208,6 +3252,7 @@ function renderModel(
32083252
task.model,
32093253
task.keyPath,
32103254
task.implicitSlot,
3255+
task.formatContext,
32113256
request.abortableTasks,
32123257
enableProfilerTimer &&
32133258
(enableComponentPerformanceTrack || enableAsyncDebugInfo)

packages/react-server/src/forks/ReactFlightServerConfig.custom.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@ export const componentStorage: AsyncLocalStorage<ReactComponentInfo | void> =
3232
export function createHints(): any {
3333
return null;
3434
}
35+
36+
export type FormatContext = null;
37+
38+
export function createRootFormatContext(): FormatContext {
39+
return null;
40+
}
41+
42+
export function getChildFormatContext(
43+
parentContext: FormatContext,
44+
type: string,
45+
props: Object,
46+
): FormatContext {
47+
return parentContext;
48+
}

packages/react-server/src/forks/ReactFlightServerConfig.dom-legacy.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@ export const componentStorage: AsyncLocalStorage<ReactComponentInfo | void> =
3232
export function createHints(): any {
3333
return null;
3434
}
35+
36+
export type FormatContext = null;
37+
38+
export function createRootFormatContext(): FormatContext {
39+
return null;
40+
}
41+
42+
export function getChildFormatContext(
43+
parentContext: FormatContext,
44+
type: string,
45+
props: Object,
46+
): FormatContext {
47+
return parentContext;
48+
}

packages/react-server/src/forks/ReactFlightServerConfig.markup.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ export function createHints(): Hints {
1919
return null;
2020
}
2121

22+
export type FormatContext = null;
23+
24+
export function createRootFormatContext(): FormatContext {
25+
return null;
26+
}
27+
28+
export function getChildFormatContext(
29+
parentContext: FormatContext,
30+
type: string,
31+
props: Object,
32+
): FormatContext {
33+
return parentContext;
34+
}
35+
2236
export const supportsRequestStorage = false;
2337
export const requestStorage: AsyncLocalStorage<Request | void> = (null: any);
2438

0 commit comments

Comments
 (0)