@@ -49,6 +49,7 @@ import type {
4949 Hints ,
5050 HintCode ,
5151 HintModel ,
52+ FormatContext ,
5253} from './ReactFlightServerConfig' ;
5354import type { ThenableState } from './ReactFlightThenable' ;
5455import 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
28212849function 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 )
0 commit comments