From ed7966e08f13dabe5793bf690677fd3a7d0a16dd Mon Sep 17 00:00:00 2001 From: acdlite Date: Wed, 13 Sep 2023 01:32:34 +0000 Subject: [PATCH] Don't modify keyPath until right before recursive renderNode call (#27366) Currently, if a component suspends, the keyPath has already been modified to include the identity of the component itself; the path is set before the component body is called (akin to the begin phase in Fiber). An accidental consequence is that when the promise resolves and component is retried, the identity gets appended to the keyPath again, leading to a duplicate node in the path. To address this, we should only modify contexts after any code that may suspend. For maximum safety, this should occur as late as possible: right before the recursive renderNode call, before the children are rendered. I did not add a test yet because there's no feature that currently observes it, but I do have tests in my other WIP PR for useFormState: #27321 DiffTrain build for [d07921eeda62613bfcf52ecdb66322db26393567](https://github.com/facebook/react/commit/d07921eeda62613bfcf52ecdb66322db26393567) --- compiled/facebook-www/REVISION | 2 +- .../ReactDOMServer-dev.classic.js | 151 +++++++++++++---- .../facebook-www/ReactDOMServer-dev.modern.js | 151 +++++++++++++---- .../ReactDOMServer-prod.classic.js | 155 +++++++++++++----- .../ReactDOMServer-prod.modern.js | 138 +++++++++++----- .../ReactDOMServerStreaming-dev.modern.js | 149 +++++++++++++---- .../ReactDOMServerStreaming-prod.modern.js | 136 ++++++++++----- .../ReactTestRenderer-dev.modern.js | 2 +- 8 files changed, 654 insertions(+), 230 deletions(-) diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index c3dae265de707..52c3152e76bb7 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -7a3cb8f9cf43591afc74722ece9e3216ccc98128 +d07921eeda62613bfcf52ecdb66322db26393567 diff --git a/compiled/facebook-www/ReactDOMServer-dev.classic.js b/compiled/facebook-www/ReactDOMServer-dev.classic.js index 8c5f9f7b652ff..caad31da69794 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.classic.js +++ b/compiled/facebook-www/ReactDOMServer-dev.classic.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require("react"); var ReactDOM = require("react-dom"); -var ReactVersion = "18.3.0-www-classic-d167ae1b"; +var ReactVersion = "18.3.0-www-classic-b080da7c"; // This refers to a WWW module. var warningWWW = require("warning"); @@ -9930,7 +9930,7 @@ function fatalError(request, error) { } } -function renderSuspenseBoundary(request, task, props) { +function renderSuspenseBoundary(request, task, keyPath, props) { pushBuiltInComponentStackInDEV(task, "Suspense"); var parentBoundary = task.blockedBoundary; var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for @@ -9941,11 +9941,7 @@ function renderSuspenseBoundary(request, task, props) { var fallback = props.fallback; var content = props.children; var fallbackAbortSet = new Set(); - var newBoundary = createSuspenseBoundary( - request, - fallbackAbortSet, - task.keyPath - ); + var newBoundary = createSuspenseBoundary(request, fallbackAbortSet, keyPath); var insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback. var boundarySegment = createPendingSegment( @@ -10043,8 +10039,8 @@ function renderSuspenseBoundary(request, task, props) { fallback, parentBoundary, boundarySegment, - fallbackAbortSet, - task.keyPath, + fallbackAbortSet, // TODO: Should distinguish key path of fallback and primary tasks + keyPath, task.formatContext, task.legacyContext, task.context, @@ -10060,7 +10056,7 @@ function renderSuspenseBoundary(request, task, props) { popComponentStackInDEV(task); } -function renderHostElement(request, task, type, props) { +function renderHostElement(request, task, keyPath, type, props) { pushBuiltInComponentStackInDEV(task, type); var segment = task.blockedSegment; var children = pushStartInstance( @@ -10074,13 +10070,16 @@ function renderHostElement(request, task, type, props) { ); segment.lastPushedText = false; var prevContext = task.formatContext; - task.formatContext = getChildFormatContext(prevContext, type, props); // We use the non-destructive form because if something suspends, we still + var prevKeyPath = task.keyPath; + task.formatContext = getChildFormatContext(prevContext, type, props); + task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still // need to pop back up and finish this subtree of HTML. renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need // the correct context. Therefore this is not in a finally. task.formatContext = prevContext; + task.keyPath = prevKeyPath; pushEndInstance( segment.chunks, type, @@ -10110,7 +10109,14 @@ function renderWithHooks( return finishHooks(Component, props, result, secondArg); } -function finishClassComponent(request, task, instance, Component, props) { +function finishClassComponent( + request, + task, + keyPath, + instance, + Component, + props +) { var nextChildren = instance.render(); { @@ -10145,15 +10151,18 @@ function finishClassComponent(request, task, instance, Component, props) { } } + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, nextChildren, -1); + task.keyPath = prevKeyPath; } -function renderClassComponent(request, task, Component, props) { +function renderClassComponent(request, task, keyPath, Component, props) { pushClassComponentStackInDEV(task, Component); var maskedContext = getMaskedContext(Component, task.legacyContext); var instance = constructClassInstance(Component, props, maskedContext); mountClassInstance(instance, Component, props, maskedContext); - finishClassComponent(request, task, instance, Component, props); + finishClassComponent(request, task, keyPath, instance, Component, props); popComponentStackInDEV(task); } @@ -10171,6 +10180,7 @@ var hasWarnedAboutUsingContextAsConsumer = false; // This would typically be a f function renderIndeterminateComponent( request, task, + keyPath, prevThenableState, Component, props @@ -10251,6 +10261,7 @@ function renderIndeterminateComponent( finishFunctionComponent( request, task, + keyPath, value, hasId, formStateCount, @@ -10264,6 +10275,7 @@ function renderIndeterminateComponent( function finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -10293,6 +10305,9 @@ function finishFunctionComponent( } } + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; + if (hasId) { // This component materialized an id. We treat this as its own level, with // a single "child" slot. @@ -10317,6 +10332,8 @@ function finishFunctionComponent( // again, so we can use the destructive recursive form. renderNodeDestructive(request, task, null, children, -1); } + + task.keyPath = prevKeyPath; } function validateFunctionComponentInDev(Component) { @@ -10393,7 +10410,15 @@ function resolveDefaultProps(Component, baseProps) { return baseProps; } -function renderForwardRef(request, task, prevThenableState, type, props, ref) { +function renderForwardRef( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { pushFunctionComponentStackInDEV(task, type.render); var children = renderWithHooks( request, @@ -10409,6 +10434,7 @@ function renderForwardRef(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -10417,12 +10443,21 @@ function renderForwardRef(request, task, prevThenableState, type, props, ref) { popComponentStackInDEV(task); } -function renderMemo(request, task, prevThenableState, type, props, ref) { +function renderMemo( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { var innerType = type.type; var resolvedProps = resolveDefaultProps(innerType, props); renderElement( request, task, + keyPath, prevThenableState, innerType, resolvedProps, @@ -10430,7 +10465,7 @@ function renderMemo(request, task, prevThenableState, type, props, ref) { ); } -function renderContextConsumer(request, task, context, props) { +function renderContextConsumer(request, task, keyPath, context, props) { // The logic below for Context differs depending on PROD or DEV mode. In // DEV mode, we create a separate object for Context.Consumer that acts // like a proxy to Context. This proxy object adds unnecessary code in PROD @@ -10473,10 +10508,13 @@ function renderContextConsumer(request, task, context, props) { var newValue = readContext$1(context); var newChildren = render(newValue); + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, newChildren, -1); + task.keyPath = prevKeyPath; } -function renderContextProvider(request, task, type, props) { +function renderContextProvider(request, task, keyPath, type, props) { var context = type._context; var value = props.value; var children = props.children; @@ -10486,9 +10524,12 @@ function renderContextProvider(request, task, type, props) { prevSnapshot = task.context; } + var prevKeyPath = task.keyPath; task.context = pushProvider(context, value); + task.keyPath = keyPath; renderNodeDestructive(request, task, null, children, -1); task.context = popProvider(context); + task.keyPath = prevKeyPath; { if (prevSnapshot !== task.context) { @@ -10502,6 +10543,7 @@ function renderContextProvider(request, task, type, props) { function renderLazyComponent( request, task, + keyPath, prevThenableState, lazyComponent, props, @@ -10515,6 +10557,7 @@ function renderLazyComponent( renderElement( request, task, + keyPath, prevThenableState, Component, resolvedProps, @@ -10523,26 +10566,38 @@ function renderLazyComponent( popComponentStackInDEV(task); } -function renderOffscreen(request, task, props) { +function renderOffscreen(request, task, keyPath, props) { var mode = props.mode; if (mode === "hidden"); else { // A visible Offscreen boundary is treated exactly like a fragment: a // pure indirection. + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = prevKeyPath; } } -function renderElement(request, task, prevThenableState, type, props, ref) { +function renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { if (typeof type === "function") { if (shouldConstruct(type)) { - renderClassComponent(request, task, type, props); + renderClassComponent(request, task, keyPath, type, props); return; } else { renderIndeterminateComponent( request, task, + keyPath, prevThenableState, type, props @@ -10552,7 +10607,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { } if (typeof type === "string") { - renderHostElement(request, task, type, props); + renderHostElement(request, task, keyPath, type, props); return; } @@ -10571,33 +10626,42 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_STRICT_MODE_TYPE: case REACT_PROFILER_TYPE: case REACT_FRAGMENT_TYPE: { + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = prevKeyPath; return; } case REACT_OFFSCREEN_TYPE: { - renderOffscreen(request, task, props); + renderOffscreen(request, task, keyPath, props); return; } case REACT_SUSPENSE_LIST_TYPE: { pushBuiltInComponentStackInDEV(task, "SuspenseList"); // TODO: SuspenseList should control the boundaries. + var _prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = _prevKeyPath; popComponentStackInDEV(task); return; } case REACT_SCOPE_TYPE: { { + var _prevKeyPath2 = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = _prevKeyPath2; return; } } case REACT_SUSPENSE_TYPE: { { - renderSuspenseBoundary(request, task, props); + renderSuspenseBoundary(request, task, keyPath, props); } return; @@ -10607,27 +10671,42 @@ function renderElement(request, task, prevThenableState, type, props, ref) { if (typeof type === "object" && type !== null) { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: { - renderForwardRef(request, task, prevThenableState, type, props, ref); + renderForwardRef( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; } case REACT_MEMO_TYPE: { - renderMemo(request, task, prevThenableState, type, props, ref); + renderMemo(request, task, keyPath, prevThenableState, type, props, ref); return; } case REACT_PROVIDER_TYPE: { - renderContextProvider(request, task, type, props); + renderContextProvider(request, task, keyPath, type, props); return; } case REACT_CONTEXT_TYPE: { - renderContextConsumer(request, task, type, props); + renderContextConsumer(request, task, keyPath, type, props); return; } case REACT_LAZY_TYPE: { - renderLazyComponent(request, task, prevThenableState, type, props); + renderLazyComponent( + request, + task, + keyPath, + prevThenableState, + type, + props + ); return; } } @@ -10747,14 +10826,20 @@ function renderNodeDestructiveImpl( var props = element.props; var ref = element.ref; var name = getComponentNameFromType(type); - var prevKeyPath = task.keyPath; - task.keyPath = [ + var keyPath = [ task.keyPath, name, key == null ? (childIndex === -1 ? 0 : childIndex) : key ]; - renderElement(request, task, prevThenableState, type, props, ref); - task.keyPath = prevKeyPath; + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; } diff --git a/compiled/facebook-www/ReactDOMServer-dev.modern.js b/compiled/facebook-www/ReactDOMServer-dev.modern.js index 85e33f48a1c58..347f0ff136ef0 100644 --- a/compiled/facebook-www/ReactDOMServer-dev.modern.js +++ b/compiled/facebook-www/ReactDOMServer-dev.modern.js @@ -19,7 +19,7 @@ if (__DEV__) { var React = require("react"); var ReactDOM = require("react-dom"); -var ReactVersion = "18.3.0-www-modern-2efbee1a"; +var ReactVersion = "18.3.0-www-modern-7c748307"; // This refers to a WWW module. var warningWWW = require("warning"); @@ -9689,7 +9689,7 @@ function fatalError(request, error) { } } -function renderSuspenseBoundary(request, task, props) { +function renderSuspenseBoundary(request, task, keyPath, props) { pushBuiltInComponentStackInDEV(task, "Suspense"); var parentBoundary = task.blockedBoundary; var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for @@ -9700,11 +9700,7 @@ function renderSuspenseBoundary(request, task, props) { var fallback = props.fallback; var content = props.children; var fallbackAbortSet = new Set(); - var newBoundary = createSuspenseBoundary( - request, - fallbackAbortSet, - task.keyPath - ); + var newBoundary = createSuspenseBoundary(request, fallbackAbortSet, keyPath); var insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback. var boundarySegment = createPendingSegment( @@ -9802,8 +9798,8 @@ function renderSuspenseBoundary(request, task, props) { fallback, parentBoundary, boundarySegment, - fallbackAbortSet, - task.keyPath, + fallbackAbortSet, // TODO: Should distinguish key path of fallback and primary tasks + keyPath, task.formatContext, task.legacyContext, task.context, @@ -9819,7 +9815,7 @@ function renderSuspenseBoundary(request, task, props) { popComponentStackInDEV(task); } -function renderHostElement(request, task, type, props) { +function renderHostElement(request, task, keyPath, type, props) { pushBuiltInComponentStackInDEV(task, type); var segment = task.blockedSegment; var children = pushStartInstance( @@ -9833,13 +9829,16 @@ function renderHostElement(request, task, type, props) { ); segment.lastPushedText = false; var prevContext = task.formatContext; - task.formatContext = getChildFormatContext(prevContext, type, props); // We use the non-destructive form because if something suspends, we still + var prevKeyPath = task.keyPath; + task.formatContext = getChildFormatContext(prevContext, type, props); + task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still // need to pop back up and finish this subtree of HTML. renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need // the correct context. Therefore this is not in a finally. task.formatContext = prevContext; + task.keyPath = prevKeyPath; pushEndInstance( segment.chunks, type, @@ -9869,7 +9868,14 @@ function renderWithHooks( return finishHooks(Component, props, result, secondArg); } -function finishClassComponent(request, task, instance, Component, props) { +function finishClassComponent( + request, + task, + keyPath, + instance, + Component, + props +) { var nextChildren = instance.render(); { @@ -9886,15 +9892,18 @@ function finishClassComponent(request, task, instance, Component, props) { } } + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, nextChildren, -1); + task.keyPath = prevKeyPath; } -function renderClassComponent(request, task, Component, props) { +function renderClassComponent(request, task, keyPath, Component, props) { pushClassComponentStackInDEV(task, Component); var maskedContext = undefined; var instance = constructClassInstance(Component, props); mountClassInstance(instance, Component, props, maskedContext); - finishClassComponent(request, task, instance, Component, props); + finishClassComponent(request, task, keyPath, instance, Component, props); popComponentStackInDEV(task); } @@ -9912,6 +9921,7 @@ var hasWarnedAboutUsingContextAsConsumer = false; // This would typically be a f function renderIndeterminateComponent( request, task, + keyPath, prevThenableState, Component, props @@ -9999,6 +10009,7 @@ function renderIndeterminateComponent( finishFunctionComponent( request, task, + keyPath, value, hasId, formStateCount, @@ -10012,6 +10023,7 @@ function renderIndeterminateComponent( function finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -10041,6 +10053,9 @@ function finishFunctionComponent( } } + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; + if (hasId) { // This component materialized an id. We treat this as its own level, with // a single "child" slot. @@ -10065,6 +10080,8 @@ function finishFunctionComponent( // again, so we can use the destructive recursive form. renderNodeDestructive(request, task, null, children, -1); } + + task.keyPath = prevKeyPath; } function validateFunctionComponentInDev(Component) { @@ -10141,7 +10158,15 @@ function resolveDefaultProps(Component, baseProps) { return baseProps; } -function renderForwardRef(request, task, prevThenableState, type, props, ref) { +function renderForwardRef( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { pushFunctionComponentStackInDEV(task, type.render); var children = renderWithHooks( request, @@ -10157,6 +10182,7 @@ function renderForwardRef(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -10165,12 +10191,21 @@ function renderForwardRef(request, task, prevThenableState, type, props, ref) { popComponentStackInDEV(task); } -function renderMemo(request, task, prevThenableState, type, props, ref) { +function renderMemo( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { var innerType = type.type; var resolvedProps = resolveDefaultProps(innerType, props); renderElement( request, task, + keyPath, prevThenableState, innerType, resolvedProps, @@ -10178,7 +10213,7 @@ function renderMemo(request, task, prevThenableState, type, props, ref) { ); } -function renderContextConsumer(request, task, context, props) { +function renderContextConsumer(request, task, keyPath, context, props) { // The logic below for Context differs depending on PROD or DEV mode. In // DEV mode, we create a separate object for Context.Consumer that acts // like a proxy to Context. This proxy object adds unnecessary code in PROD @@ -10221,10 +10256,13 @@ function renderContextConsumer(request, task, context, props) { var newValue = readContext$1(context); var newChildren = render(newValue); + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, newChildren, -1); + task.keyPath = prevKeyPath; } -function renderContextProvider(request, task, type, props) { +function renderContextProvider(request, task, keyPath, type, props) { var context = type._context; var value = props.value; var children = props.children; @@ -10234,9 +10272,12 @@ function renderContextProvider(request, task, type, props) { prevSnapshot = task.context; } + var prevKeyPath = task.keyPath; task.context = pushProvider(context, value); + task.keyPath = keyPath; renderNodeDestructive(request, task, null, children, -1); task.context = popProvider(context); + task.keyPath = prevKeyPath; { if (prevSnapshot !== task.context) { @@ -10250,6 +10291,7 @@ function renderContextProvider(request, task, type, props) { function renderLazyComponent( request, task, + keyPath, prevThenableState, lazyComponent, props, @@ -10263,6 +10305,7 @@ function renderLazyComponent( renderElement( request, task, + keyPath, prevThenableState, Component, resolvedProps, @@ -10271,26 +10314,38 @@ function renderLazyComponent( popComponentStackInDEV(task); } -function renderOffscreen(request, task, props) { +function renderOffscreen(request, task, keyPath, props) { var mode = props.mode; if (mode === "hidden"); else { // A visible Offscreen boundary is treated exactly like a fragment: a // pure indirection. + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = prevKeyPath; } } -function renderElement(request, task, prevThenableState, type, props, ref) { +function renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { if (typeof type === "function") { if (shouldConstruct(type)) { - renderClassComponent(request, task, type, props); + renderClassComponent(request, task, keyPath, type, props); return; } else { renderIndeterminateComponent( request, task, + keyPath, prevThenableState, type, props @@ -10300,7 +10355,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { } if (typeof type === "string") { - renderHostElement(request, task, type, props); + renderHostElement(request, task, keyPath, type, props); return; } @@ -10319,33 +10374,42 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_STRICT_MODE_TYPE: case REACT_PROFILER_TYPE: case REACT_FRAGMENT_TYPE: { + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = prevKeyPath; return; } case REACT_OFFSCREEN_TYPE: { - renderOffscreen(request, task, props); + renderOffscreen(request, task, keyPath, props); return; } case REACT_SUSPENSE_LIST_TYPE: { pushBuiltInComponentStackInDEV(task, "SuspenseList"); // TODO: SuspenseList should control the boundaries. + var _prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = _prevKeyPath; popComponentStackInDEV(task); return; } case REACT_SCOPE_TYPE: { { + var _prevKeyPath2 = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = _prevKeyPath2; return; } } case REACT_SUSPENSE_TYPE: { { - renderSuspenseBoundary(request, task, props); + renderSuspenseBoundary(request, task, keyPath, props); } return; @@ -10355,27 +10419,42 @@ function renderElement(request, task, prevThenableState, type, props, ref) { if (typeof type === "object" && type !== null) { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: { - renderForwardRef(request, task, prevThenableState, type, props, ref); + renderForwardRef( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; } case REACT_MEMO_TYPE: { - renderMemo(request, task, prevThenableState, type, props, ref); + renderMemo(request, task, keyPath, prevThenableState, type, props, ref); return; } case REACT_PROVIDER_TYPE: { - renderContextProvider(request, task, type, props); + renderContextProvider(request, task, keyPath, type, props); return; } case REACT_CONTEXT_TYPE: { - renderContextConsumer(request, task, type, props); + renderContextConsumer(request, task, keyPath, type, props); return; } case REACT_LAZY_TYPE: { - renderLazyComponent(request, task, prevThenableState, type, props); + renderLazyComponent( + request, + task, + keyPath, + prevThenableState, + type, + props + ); return; } } @@ -10495,14 +10574,20 @@ function renderNodeDestructiveImpl( var props = element.props; var ref = element.ref; var name = getComponentNameFromType(type); - var prevKeyPath = task.keyPath; - task.keyPath = [ + var keyPath = [ task.keyPath, name, key == null ? (childIndex === -1 ? 0 : childIndex) : key ]; - renderElement(request, task, prevThenableState, type, props, ref); - task.keyPath = prevKeyPath; + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; } diff --git a/compiled/facebook-www/ReactDOMServer-prod.classic.js b/compiled/facebook-www/ReactDOMServer-prod.classic.js index 79181ec8bacab..985ad3d2522f4 100644 --- a/compiled/facebook-www/ReactDOMServer-prod.classic.js +++ b/compiled/facebook-www/ReactDOMServer-prod.classic.js @@ -3009,6 +3009,7 @@ function fatalError(request, error) { function finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -3026,14 +3027,17 @@ function finishFunctionComponent( : segment.push("\x3c!--F--\x3e"); } } + formStateCount = task.keyPath; + task.keyPath = keyPath; hasId - ? ((hasId = task.treeContext), - (task.treeContext = pushTreeContext(hasId, 1, 0)), + ? ((keyPath = task.treeContext), + (task.treeContext = pushTreeContext(keyPath, 1, 0)), renderNode(request, task, children, -1), - (task.treeContext = hasId)) + (task.treeContext = keyPath)) : didEmitFormStateMarkers ? renderNode(request, task, children, -1) : renderNodeDestructiveImpl(request, task, null, children, -1); + task.keyPath = formStateCount; } function resolveDefaultProps(Component, baseProps) { if (Component && Component.defaultProps) { @@ -3046,7 +3050,15 @@ function resolveDefaultProps(Component, baseProps) { } return baseProps; } -function renderElement(request, task, prevThenableState, type, props, ref) { +function renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { if ("function" === typeof type) if (type.prototype && type.prototype.isReactComponent) { prevThenableState = getMaskedContext(type, task.legacyContext); @@ -3136,15 +3148,15 @@ function renderElement(request, task, prevThenableState, type, props, ref) { } } else ref.queue = null; props = JSCompiler_inline_result.render(); - ref = type.childContextTypes; - if (null !== ref && void 0 !== ref) { - prevThenableState = task.legacyContext; + prevThenableState = type.childContextTypes; + if (null !== prevThenableState && void 0 !== prevThenableState) { + keyPath = task.legacyContext; if ("function" !== typeof JSCompiler_inline_result.getChildContext) - type = prevThenableState; + type = keyPath; else { JSCompiler_inline_result = JSCompiler_inline_result.getChildContext(); for (var contextKey in JSCompiler_inline_result) - if (!(contextKey in ref)) + if (!(contextKey in prevThenableState)) throw Error( formatProdErrorMessage( 108, @@ -3152,12 +3164,16 @@ function renderElement(request, task, prevThenableState, type, props, ref) { contextKey ) ); - type = assign({}, prevThenableState, JSCompiler_inline_result); + type = assign({}, keyPath, JSCompiler_inline_result); } task.legacyContext = type; renderNodeDestructiveImpl(request, task, null, props, -1); - task.legacyContext = prevThenableState; - } else renderNodeDestructiveImpl(request, task, null, props, -1); + task.legacyContext = keyPath; + } else + (type = task.keyPath), + (task.keyPath = keyPath), + renderNodeDestructiveImpl(request, task, null, props, -1), + (task.keyPath = type); } else (contextKey = getMaskedContext(type, task.legacyContext)), (currentlyRenderingComponent = {}), @@ -3176,6 +3192,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, props, 0 !== localIdCounter, formStateCounter, @@ -3194,13 +3211,16 @@ function renderElement(request, task, prevThenableState, type, props, ref) { ); contextKey.lastPushedText = !1; JSCompiler_inline_result = task.formatContext; + ref = task.keyPath; task.formatContext = getChildFormatContext( JSCompiler_inline_result, type, props ); + task.keyPath = keyPath; renderNode(request, task, prevThenableState, -1); task.formatContext = JSCompiler_inline_result; + task.keyPath = ref; a: { task = contextKey.chunks; request = request.resumableState; @@ -3246,17 +3266,29 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_STRICT_MODE_TYPE: case REACT_PROFILER_TYPE: case REACT_FRAGMENT_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_OFFSCREEN_TYPE: "hidden" !== props.mode && - renderNodeDestructiveImpl(request, task, null, props.children, -1); + ((type = task.keyPath), + (task.keyPath = keyPath), + renderNodeDestructiveImpl(request, task, null, props.children, -1), + (task.keyPath = type)); return; case REACT_SUSPENSE_LIST_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_SCOPE_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_SUSPENSE_TYPE: a: { @@ -3265,7 +3297,6 @@ function renderElement(request, task, prevThenableState, type, props, ref) { prevThenableState = props.fallback; props = props.children; ref = new Set(); - initialState = task.keyPath; initialState = { status: 0, id: null, @@ -3277,7 +3308,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { fallbackAbortableTasks: ref, errorDigest: null, resources: new Set(), - keyPath: initialState + keyPath: keyPath }; contextType = createPendingSegment( request, @@ -3334,7 +3365,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { type, contextType, ref, - task.keyPath, + keyPath, task.formatContext, task.legacyContext, task.context, @@ -3359,6 +3390,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, props, 0 !== localIdCounter, formStateCounter, @@ -3368,44 +3400,72 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_MEMO_TYPE: type = type.type; props = resolveDefaultProps(type, props); - renderElement(request, task, prevThenableState, type, props, ref); + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; case REACT_PROVIDER_TYPE: - contextKey = props.children; + JSCompiler_inline_result = props.children; + contextKey = task.keyPath; type = type._context; props = props.value; - JSCompiler_inline_result = type._currentValue2; + prevThenableState = type._currentValue2; type._currentValue2 = props; - prevThenableState = currentActiveSnapshot; + ref = currentActiveSnapshot; currentActiveSnapshot = props = { - parent: prevThenableState, - depth: null === prevThenableState ? 0 : prevThenableState.depth + 1, + parent: ref, + depth: null === ref ? 0 : ref.depth + 1, context: type, - parentValue: JSCompiler_inline_result, + parentValue: prevThenableState, value: props }; task.context = props; - renderNodeDestructiveImpl(request, task, null, contextKey, -1); + task.keyPath = keyPath; + renderNodeDestructiveImpl( + request, + task, + null, + JSCompiler_inline_result, + -1 + ); request = currentActiveSnapshot; if (null === request) throw Error(formatProdErrorMessage(403)); - props = request.parentValue; + keyPath = request.parentValue; request.context._currentValue2 = - props === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED + keyPath === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED ? request.context._defaultValue - : props; + : keyPath; request = currentActiveSnapshot = request.parent; task.context = request; + task.keyPath = contextKey; return; case REACT_CONTEXT_TYPE: props = props.children; props = props(type._currentValue2); + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props, -1); + task.keyPath = type; return; case REACT_LAZY_TYPE: contextKey = type._init; type = contextKey(type._payload); props = resolveDefaultProps(type, props); - renderElement(request, task, prevThenableState, type, props, void 0); + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + void 0 + ); return; } throw Error( @@ -3429,15 +3489,20 @@ function renderNodeDestructiveImpl( key = node.key, props = node.props; node = node.ref; - var name = getComponentNameFromType(type), - prevKeyPath = task.keyPath; - task.keyPath = [ - task.keyPath, - name, - null == key ? (-1 === childIndex ? 0 : childIndex) : key - ]; - renderElement(request, task, prevThenableState, type, props, node); - task.keyPath = prevKeyPath; + var name = getComponentNameFromType(type); + renderElement( + request, + task, + [ + task.keyPath, + name, + null == key ? (-1 === childIndex ? 0 : childIndex) : key + ], + prevThenableState, + type, + props, + node + ); return; case REACT_PORTAL_TYPE: throw Error(formatProdErrorMessage(257)); @@ -4255,13 +4320,13 @@ function flushCompletedQueues(request, destination) { completedBoundaries.splice(0, i); var partialBoundaries = request.partialBoundaries; for (i = 0; i < partialBoundaries.length; i++) { - var boundary$13 = partialBoundaries[i]; + var boundary$15 = partialBoundaries[i]; a: { clientRenderedBoundaries = request; boundary = destination; clientRenderedBoundaries.renderState.boundaryResources = - boundary$13.resources; - var completedSegments = boundary$13.completedSegments; + boundary$15.resources; + var completedSegments = boundary$15.completedSegments; for ( resumableState$jscomp$1 = 0; resumableState$jscomp$1 < completedSegments.length; @@ -4271,7 +4336,7 @@ function flushCompletedQueues(request, destination) { !flushPartiallyCompletedSegment( clientRenderedBoundaries, boundary, - boundary$13, + boundary$15, completedSegments[resumableState$jscomp$1] ) ) { @@ -4283,7 +4348,7 @@ function flushCompletedQueues(request, destination) { completedSegments.splice(0, resumableState$jscomp$1); JSCompiler_inline_result = writeResourcesForBoundary( boundary, - boundary$13.resources, + boundary$15.resources, clientRenderedBoundaries.renderState ); } @@ -4346,8 +4411,8 @@ function abort(request, reason) { } null !== request.destination && flushCompletedQueues(request, request.destination); - } catch (error$15) { - logRecoverableError(request, error$15), fatalError(request, error$15); + } catch (error$17) { + logRecoverableError(request, error$17), fatalError(request, error$17); } } function onError() {} @@ -4434,4 +4499,4 @@ exports.renderToString = function (children, options) { 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server' ); }; -exports.version = "18.3.0-www-classic-d6f252d2"; +exports.version = "18.3.0-www-classic-10a5a8c2"; diff --git a/compiled/facebook-www/ReactDOMServer-prod.modern.js b/compiled/facebook-www/ReactDOMServer-prod.modern.js index 913b87376e7d1..9c5d4f744d98e 100644 --- a/compiled/facebook-www/ReactDOMServer-prod.modern.js +++ b/compiled/facebook-www/ReactDOMServer-prod.modern.js @@ -3001,6 +3001,7 @@ function fatalError(request, error) { function finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -3018,14 +3019,17 @@ function finishFunctionComponent( : segment.push("\x3c!--F--\x3e"); } } + formStateCount = task.keyPath; + task.keyPath = keyPath; hasId - ? ((hasId = task.treeContext), - (task.treeContext = pushTreeContext(hasId, 1, 0)), + ? ((keyPath = task.treeContext), + (task.treeContext = pushTreeContext(keyPath, 1, 0)), renderNode(request, task, children, -1), - (task.treeContext = hasId)) + (task.treeContext = keyPath)) : didEmitFormStateMarkers ? renderNode(request, task, children, -1) : renderNodeDestructiveImpl(request, task, null, children, -1); + task.keyPath = formStateCount; } function resolveDefaultProps(Component, baseProps) { if (Component && Component.defaultProps) { @@ -3038,7 +3042,15 @@ function resolveDefaultProps(Component, baseProps) { } return baseProps; } -function renderElement(request, task, prevThenableState, type, props, ref) { +function renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { if ("function" === typeof type) if (type.prototype && type.prototype.isReactComponent) { var JSCompiler_inline_result = emptyContextObject; @@ -3135,7 +3147,10 @@ function renderElement(request, task, prevThenableState, type, props, ref) { } else prevThenableState.queue = null; props = JSCompiler_inline_result.render(); + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props, -1); + task.keyPath = type; } else (currentlyRenderingComponent = {}), (currentlyRenderingTask = task), @@ -3148,6 +3163,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, props, 0 !== localIdCounter, formStateCounter, @@ -3166,9 +3182,12 @@ function renderElement(request, task, prevThenableState, type, props, ref) { ); JSCompiler_inline_result.lastPushedText = !1; prevThenableState = task.formatContext; + contextType = task.keyPath; task.formatContext = getChildFormatContext(prevThenableState, type, props); + task.keyPath = keyPath; renderNode(request, task, ref, -1); task.formatContext = prevThenableState; + task.keyPath = contextType; a: { task = JSCompiler_inline_result.chunks; request = request.resumableState; @@ -3214,17 +3233,29 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_STRICT_MODE_TYPE: case REACT_PROFILER_TYPE: case REACT_FRAGMENT_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_OFFSCREEN_TYPE: "hidden" !== props.mode && - renderNodeDestructiveImpl(request, task, null, props.children, -1); + ((type = task.keyPath), + (task.keyPath = keyPath), + renderNodeDestructiveImpl(request, task, null, props.children, -1), + (task.keyPath = type)); return; case REACT_SUSPENSE_LIST_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_SCOPE_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_SUSPENSE_TYPE: a: { @@ -3233,7 +3264,6 @@ function renderElement(request, task, prevThenableState, type, props, ref) { ref = props.fallback; props = props.children; contextType = new Set(); - partial = task.keyPath; partial = { status: 0, id: null, @@ -3245,7 +3275,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { fallbackAbortableTasks: contextType, errorDigest: null, resources: new Set(), - keyPath: partial + keyPath: keyPath }; var boundarySegment = createPendingSegment( request, @@ -3302,7 +3332,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { type, boundarySegment, contextType, - task.keyPath, + keyPath, task.formatContext, task.legacyContext, task.context, @@ -3327,6 +3357,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, props, 0 !== localIdCounter, formStateCounter, @@ -3336,50 +3367,66 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_MEMO_TYPE: type = type.type; props = resolveDefaultProps(type, props); - renderElement(request, task, prevThenableState, type, props, ref); + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; case REACT_PROVIDER_TYPE: - JSCompiler_inline_result = props.children; + prevThenableState = props.children; + JSCompiler_inline_result = task.keyPath; type = type._context; props = props.value; - prevThenableState = type._currentValue2; + ref = type._currentValue2; type._currentValue2 = props; - ref = currentActiveSnapshot; + contextType = currentActiveSnapshot; currentActiveSnapshot = props = { - parent: ref, - depth: null === ref ? 0 : ref.depth + 1, + parent: contextType, + depth: null === contextType ? 0 : contextType.depth + 1, context: type, - parentValue: prevThenableState, + parentValue: ref, value: props }; task.context = props; - renderNodeDestructiveImpl( - request, - task, - null, - JSCompiler_inline_result, - -1 - ); + task.keyPath = keyPath; + renderNodeDestructiveImpl(request, task, null, prevThenableState, -1); request = currentActiveSnapshot; if (null === request) throw Error(formatProdErrorMessage(403)); - props = request.parentValue; + keyPath = request.parentValue; request.context._currentValue2 = - props === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED + keyPath === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED ? request.context._defaultValue - : props; + : keyPath; request = currentActiveSnapshot = request.parent; task.context = request; + task.keyPath = JSCompiler_inline_result; return; case REACT_CONTEXT_TYPE: props = props.children; props = props(type._currentValue2); + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props, -1); + task.keyPath = type; return; case REACT_LAZY_TYPE: JSCompiler_inline_result = type._init; type = JSCompiler_inline_result(type._payload); props = resolveDefaultProps(type, props); - renderElement(request, task, prevThenableState, type, props, void 0); + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + void 0 + ); return; } throw Error( @@ -3403,15 +3450,20 @@ function renderNodeDestructiveImpl( key = node.key, props = node.props; node = node.ref; - var name = getComponentNameFromType(type), - prevKeyPath = task.keyPath; - task.keyPath = [ - task.keyPath, - name, - null == key ? (-1 === childIndex ? 0 : childIndex) : key - ]; - renderElement(request, task, prevThenableState, type, props, node); - task.keyPath = prevKeyPath; + var name = getComponentNameFromType(type); + renderElement( + request, + task, + [ + task.keyPath, + name, + null == key ? (-1 === childIndex ? 0 : childIndex) : key + ], + prevThenableState, + type, + props, + node + ); return; case REACT_PORTAL_TYPE: throw Error(formatProdErrorMessage(257)); @@ -4229,13 +4281,13 @@ function flushCompletedQueues(request, destination) { completedBoundaries.splice(0, i); var partialBoundaries = request.partialBoundaries; for (i = 0; i < partialBoundaries.length; i++) { - var boundary$13 = partialBoundaries[i]; + var boundary$15 = partialBoundaries[i]; a: { clientRenderedBoundaries = request; boundary = destination; clientRenderedBoundaries.renderState.boundaryResources = - boundary$13.resources; - var completedSegments = boundary$13.completedSegments; + boundary$15.resources; + var completedSegments = boundary$15.completedSegments; for ( resumableState$jscomp$1 = 0; resumableState$jscomp$1 < completedSegments.length; @@ -4245,7 +4297,7 @@ function flushCompletedQueues(request, destination) { !flushPartiallyCompletedSegment( clientRenderedBoundaries, boundary, - boundary$13, + boundary$15, completedSegments[resumableState$jscomp$1] ) ) { @@ -4257,7 +4309,7 @@ function flushCompletedQueues(request, destination) { completedSegments.splice(0, resumableState$jscomp$1); JSCompiler_inline_result = writeResourcesForBoundary( boundary, - boundary$13.resources, + boundary$15.resources, clientRenderedBoundaries.renderState ); } @@ -4320,8 +4372,8 @@ function abort(request, reason) { } null !== request.destination && flushCompletedQueues(request, request.destination); - } catch (error$15) { - logRecoverableError(request, error$15), fatalError(request, error$15); + } catch (error$17) { + logRecoverableError(request, error$17), fatalError(request, error$17); } } function onError() {} @@ -4408,4 +4460,4 @@ exports.renderToString = function (children, options) { 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server' ); }; -exports.version = "18.3.0-www-modern-a9d281fb"; +exports.version = "18.3.0-www-modern-c2a4cb0f"; diff --git a/compiled/facebook-www/ReactDOMServerStreaming-dev.modern.js b/compiled/facebook-www/ReactDOMServerStreaming-dev.modern.js index cb1f3ae42613c..d3622ed992256 100644 --- a/compiled/facebook-www/ReactDOMServerStreaming-dev.modern.js +++ b/compiled/facebook-www/ReactDOMServerStreaming-dev.modern.js @@ -9592,7 +9592,7 @@ function fatalError(request, error) { } } -function renderSuspenseBoundary(request, task, props) { +function renderSuspenseBoundary(request, task, keyPath, props) { pushBuiltInComponentStackInDEV(task, "Suspense"); var parentBoundary = task.blockedBoundary; var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for @@ -9603,11 +9603,7 @@ function renderSuspenseBoundary(request, task, props) { var fallback = props.fallback; var content = props.children; var fallbackAbortSet = new Set(); - var newBoundary = createSuspenseBoundary( - request, - fallbackAbortSet, - task.keyPath - ); + var newBoundary = createSuspenseBoundary(request, fallbackAbortSet, keyPath); var insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback. var boundarySegment = createPendingSegment( @@ -9705,8 +9701,8 @@ function renderSuspenseBoundary(request, task, props) { fallback, parentBoundary, boundarySegment, - fallbackAbortSet, - task.keyPath, + fallbackAbortSet, // TODO: Should distinguish key path of fallback and primary tasks + keyPath, task.formatContext, task.legacyContext, task.context, @@ -9722,7 +9718,7 @@ function renderSuspenseBoundary(request, task, props) { popComponentStackInDEV(task); } -function renderHostElement(request, task, type, props) { +function renderHostElement(request, task, keyPath, type, props) { pushBuiltInComponentStackInDEV(task, type); var segment = task.blockedSegment; var children = pushStartInstance( @@ -9736,13 +9732,16 @@ function renderHostElement(request, task, type, props) { ); segment.lastPushedText = false; var prevContext = task.formatContext; - task.formatContext = getChildFormatContext(prevContext, type, props); // We use the non-destructive form because if something suspends, we still + var prevKeyPath = task.keyPath; + task.formatContext = getChildFormatContext(prevContext, type, props); + task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still // need to pop back up and finish this subtree of HTML. renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need // the correct context. Therefore this is not in a finally. task.formatContext = prevContext; + task.keyPath = prevKeyPath; pushEndInstance( segment.chunks, type, @@ -9772,7 +9771,14 @@ function renderWithHooks( return finishHooks(Component, props, result, secondArg); } -function finishClassComponent(request, task, instance, Component, props) { +function finishClassComponent( + request, + task, + keyPath, + instance, + Component, + props +) { var nextChildren = instance.render(); { @@ -9789,15 +9795,18 @@ function finishClassComponent(request, task, instance, Component, props) { } } + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, nextChildren, -1); + task.keyPath = prevKeyPath; } -function renderClassComponent(request, task, Component, props) { +function renderClassComponent(request, task, keyPath, Component, props) { pushClassComponentStackInDEV(task, Component); var maskedContext = undefined; var instance = constructClassInstance(Component, props); mountClassInstance(instance, Component, props, maskedContext); - finishClassComponent(request, task, instance, Component, props); + finishClassComponent(request, task, keyPath, instance, Component, props); popComponentStackInDEV(task); } @@ -9815,6 +9824,7 @@ var hasWarnedAboutUsingContextAsConsumer = false; // This would typically be a f function renderIndeterminateComponent( request, task, + keyPath, prevThenableState, Component, props @@ -9902,6 +9912,7 @@ function renderIndeterminateComponent( finishFunctionComponent( request, task, + keyPath, value, hasId, formStateCount, @@ -9915,6 +9926,7 @@ function renderIndeterminateComponent( function finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -9944,6 +9956,9 @@ function finishFunctionComponent( } } + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; + if (hasId) { // This component materialized an id. We treat this as its own level, with // a single "child" slot. @@ -9968,6 +9983,8 @@ function finishFunctionComponent( // again, so we can use the destructive recursive form. renderNodeDestructive(request, task, null, children, -1); } + + task.keyPath = prevKeyPath; } function validateFunctionComponentInDev(Component) { @@ -10044,7 +10061,15 @@ function resolveDefaultProps(Component, baseProps) { return baseProps; } -function renderForwardRef(request, task, prevThenableState, type, props, ref) { +function renderForwardRef( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { pushFunctionComponentStackInDEV(task, type.render); var children = renderWithHooks( request, @@ -10060,6 +10085,7 @@ function renderForwardRef(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -10068,12 +10094,21 @@ function renderForwardRef(request, task, prevThenableState, type, props, ref) { popComponentStackInDEV(task); } -function renderMemo(request, task, prevThenableState, type, props, ref) { +function renderMemo( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { var innerType = type.type; var resolvedProps = resolveDefaultProps(innerType, props); renderElement( request, task, + keyPath, prevThenableState, innerType, resolvedProps, @@ -10081,7 +10116,7 @@ function renderMemo(request, task, prevThenableState, type, props, ref) { ); } -function renderContextConsumer(request, task, context, props) { +function renderContextConsumer(request, task, keyPath, context, props) { // The logic below for Context differs depending on PROD or DEV mode. In // DEV mode, we create a separate object for Context.Consumer that acts // like a proxy to Context. This proxy object adds unnecessary code in PROD @@ -10124,10 +10159,13 @@ function renderContextConsumer(request, task, context, props) { var newValue = readContext$1(context); var newChildren = render(newValue); + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, newChildren, -1); + task.keyPath = prevKeyPath; } -function renderContextProvider(request, task, type, props) { +function renderContextProvider(request, task, keyPath, type, props) { var context = type._context; var value = props.value; var children = props.children; @@ -10137,9 +10175,12 @@ function renderContextProvider(request, task, type, props) { prevSnapshot = task.context; } + var prevKeyPath = task.keyPath; task.context = pushProvider(context, value); + task.keyPath = keyPath; renderNodeDestructive(request, task, null, children, -1); task.context = popProvider(context); + task.keyPath = prevKeyPath; { if (prevSnapshot !== task.context) { @@ -10153,6 +10194,7 @@ function renderContextProvider(request, task, type, props) { function renderLazyComponent( request, task, + keyPath, prevThenableState, lazyComponent, props, @@ -10166,6 +10208,7 @@ function renderLazyComponent( renderElement( request, task, + keyPath, prevThenableState, Component, resolvedProps, @@ -10174,26 +10217,38 @@ function renderLazyComponent( popComponentStackInDEV(task); } -function renderOffscreen(request, task, props) { +function renderOffscreen(request, task, keyPath, props) { var mode = props.mode; if (mode === "hidden"); else { // A visible Offscreen boundary is treated exactly like a fragment: a // pure indirection. + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = prevKeyPath; } } -function renderElement(request, task, prevThenableState, type, props, ref) { +function renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { if (typeof type === "function") { if (shouldConstruct(type)) { - renderClassComponent(request, task, type, props); + renderClassComponent(request, task, keyPath, type, props); return; } else { renderIndeterminateComponent( request, task, + keyPath, prevThenableState, type, props @@ -10203,7 +10258,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { } if (typeof type === "string") { - renderHostElement(request, task, type, props); + renderHostElement(request, task, keyPath, type, props); return; } @@ -10222,33 +10277,42 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_STRICT_MODE_TYPE: case REACT_PROFILER_TYPE: case REACT_FRAGMENT_TYPE: { + var prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = prevKeyPath; return; } case REACT_OFFSCREEN_TYPE: { - renderOffscreen(request, task, props); + renderOffscreen(request, task, keyPath, props); return; } case REACT_SUSPENSE_LIST_TYPE: { pushBuiltInComponentStackInDEV(task, "SuspenseList"); // TODO: SuspenseList should control the boundaries. + var _prevKeyPath = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = _prevKeyPath; popComponentStackInDEV(task); return; } case REACT_SCOPE_TYPE: { { + var _prevKeyPath2 = task.keyPath; + task.keyPath = keyPath; renderNodeDestructive(request, task, null, props.children, -1); + task.keyPath = _prevKeyPath2; return; } } case REACT_SUSPENSE_TYPE: { { - renderSuspenseBoundary(request, task, props); + renderSuspenseBoundary(request, task, keyPath, props); } return; @@ -10258,27 +10322,42 @@ function renderElement(request, task, prevThenableState, type, props, ref) { if (typeof type === "object" && type !== null) { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: { - renderForwardRef(request, task, prevThenableState, type, props, ref); + renderForwardRef( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; } case REACT_MEMO_TYPE: { - renderMemo(request, task, prevThenableState, type, props, ref); + renderMemo(request, task, keyPath, prevThenableState, type, props, ref); return; } case REACT_PROVIDER_TYPE: { - renderContextProvider(request, task, type, props); + renderContextProvider(request, task, keyPath, type, props); return; } case REACT_CONTEXT_TYPE: { - renderContextConsumer(request, task, type, props); + renderContextConsumer(request, task, keyPath, type, props); return; } case REACT_LAZY_TYPE: { - renderLazyComponent(request, task, prevThenableState, type, props); + renderLazyComponent( + request, + task, + keyPath, + prevThenableState, + type, + props + ); return; } } @@ -10398,14 +10477,20 @@ function renderNodeDestructiveImpl( var props = element.props; var ref = element.ref; var name = getComponentNameFromType(type); - var prevKeyPath = task.keyPath; - task.keyPath = [ + var keyPath = [ task.keyPath, name, key == null ? (childIndex === -1 ? 0 : childIndex) : key ]; - renderElement(request, task, prevThenableState, type, props, ref); - task.keyPath = prevKeyPath; + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; } diff --git a/compiled/facebook-www/ReactDOMServerStreaming-prod.modern.js b/compiled/facebook-www/ReactDOMServerStreaming-prod.modern.js index 494905c1d21f6..32c4c5861ccd4 100644 --- a/compiled/facebook-www/ReactDOMServerStreaming-prod.modern.js +++ b/compiled/facebook-www/ReactDOMServerStreaming-prod.modern.js @@ -2798,6 +2798,7 @@ function fatalError(request, error) { function finishFunctionComponent( request, task, + keyPath, children, hasId, formStateCount, @@ -2815,14 +2816,17 @@ function finishFunctionComponent( : segment.push("\x3c!--F--\x3e"); } } + formStateCount = task.keyPath; + task.keyPath = keyPath; hasId - ? ((hasId = task.treeContext), - (task.treeContext = pushTreeContext(hasId, 1, 0)), + ? ((keyPath = task.treeContext), + (task.treeContext = pushTreeContext(keyPath, 1, 0)), renderNode(request, task, children, -1), - (task.treeContext = hasId)) + (task.treeContext = keyPath)) : didEmitFormStateMarkers ? renderNode(request, task, children, -1) : renderNodeDestructiveImpl(request, task, null, children, -1); + task.keyPath = formStateCount; } function resolveDefaultProps(Component, baseProps) { if (Component && Component.defaultProps) { @@ -2835,7 +2839,15 @@ function resolveDefaultProps(Component, baseProps) { } return baseProps; } -function renderElement(request, task, prevThenableState, type, props, ref) { +function renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref +) { if ("function" === typeof type) if (type.prototype && type.prototype.isReactComponent) { var JSCompiler_inline_result = emptyContextObject; @@ -2932,7 +2944,10 @@ function renderElement(request, task, prevThenableState, type, props, ref) { } else prevThenableState.queue = null; props = JSCompiler_inline_result.render(); + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props, -1); + task.keyPath = type; } else (currentlyRenderingComponent = {}), (currentlyRenderingTask = task), @@ -2945,6 +2960,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, props, 0 !== localIdCounter, formStateCounter, @@ -2963,9 +2979,12 @@ function renderElement(request, task, prevThenableState, type, props, ref) { ); JSCompiler_inline_result.lastPushedText = !1; prevThenableState = task.formatContext; + contextType = task.keyPath; task.formatContext = getChildFormatContext(prevThenableState, type, props); + task.keyPath = keyPath; renderNode(request, task, ref, -1); task.formatContext = prevThenableState; + task.keyPath = contextType; a: { task = JSCompiler_inline_result.chunks; request = request.resumableState; @@ -3011,17 +3030,29 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_STRICT_MODE_TYPE: case REACT_PROFILER_TYPE: case REACT_FRAGMENT_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_OFFSCREEN_TYPE: "hidden" !== props.mode && - renderNodeDestructiveImpl(request, task, null, props.children, -1); + ((type = task.keyPath), + (task.keyPath = keyPath), + renderNodeDestructiveImpl(request, task, null, props.children, -1), + (task.keyPath = type)); return; case REACT_SUSPENSE_LIST_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_SCOPE_TYPE: + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props.children, -1); + task.keyPath = type; return; case REACT_SUSPENSE_TYPE: a: { @@ -3030,7 +3061,6 @@ function renderElement(request, task, prevThenableState, type, props, ref) { ref = props.fallback; props = props.children; contextType = new Set(); - partial = task.keyPath; partial = { status: 0, id: null, @@ -3042,7 +3072,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { fallbackAbortableTasks: contextType, errorDigest: null, resources: new Set(), - keyPath: partial + keyPath: keyPath }; var boundarySegment = createPendingSegment( request, @@ -3098,7 +3128,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { type, boundarySegment, contextType, - task.keyPath, + keyPath, task.formatContext, task.legacyContext, task.context, @@ -3123,6 +3153,7 @@ function renderElement(request, task, prevThenableState, type, props, ref) { finishFunctionComponent( request, task, + keyPath, props, 0 !== localIdCounter, formStateCounter, @@ -3132,53 +3163,69 @@ function renderElement(request, task, prevThenableState, type, props, ref) { case REACT_MEMO_TYPE: type = type.type; props = resolveDefaultProps(type, props); - renderElement(request, task, prevThenableState, type, props, ref); + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + ref + ); return; case REACT_PROVIDER_TYPE: - JSCompiler_inline_result = props.children; + prevThenableState = props.children; + JSCompiler_inline_result = task.keyPath; type = type._context; props = props.value; - prevThenableState = type._currentValue; + ref = type._currentValue; type._currentValue = props; - ref = currentActiveSnapshot; + contextType = currentActiveSnapshot; currentActiveSnapshot = props = { - parent: ref, - depth: null === ref ? 0 : ref.depth + 1, + parent: contextType, + depth: null === contextType ? 0 : contextType.depth + 1, context: type, - parentValue: prevThenableState, + parentValue: ref, value: props }; task.context = props; - renderNodeDestructiveImpl( - request, - task, - null, - JSCompiler_inline_result, - -1 - ); + task.keyPath = keyPath; + renderNodeDestructiveImpl(request, task, null, prevThenableState, -1); request = currentActiveSnapshot; if (null === request) throw Error( "Tried to pop a Context at the root of the app. This is a bug in React." ); - props = request.parentValue; + keyPath = request.parentValue; request.context._currentValue = - props === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED + keyPath === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED ? request.context._defaultValue - : props; + : keyPath; request = currentActiveSnapshot = request.parent; task.context = request; + task.keyPath = JSCompiler_inline_result; return; case REACT_CONTEXT_TYPE: props = props.children; props = props(type._currentValue); + type = task.keyPath; + task.keyPath = keyPath; renderNodeDestructiveImpl(request, task, null, props, -1); + task.keyPath = type; return; case REACT_LAZY_TYPE: JSCompiler_inline_result = type._init; type = JSCompiler_inline_result(type._payload); props = resolveDefaultProps(type, props); - renderElement(request, task, prevThenableState, type, props, void 0); + renderElement( + request, + task, + keyPath, + prevThenableState, + type, + props, + void 0 + ); return; } throw Error( @@ -3203,15 +3250,20 @@ function renderNodeDestructiveImpl( key = node.key, props = node.props; node = node.ref; - var name = getComponentNameFromType(type), - prevKeyPath = task.keyPath; - task.keyPath = [ - task.keyPath, - name, - null == key ? (-1 === childIndex ? 0 : childIndex) : key - ]; - renderElement(request, task, prevThenableState, type, props, node); - task.keyPath = prevKeyPath; + var name = getComponentNameFromType(type); + renderElement( + request, + task, + [ + task.keyPath, + name, + null == key ? (-1 === childIndex ? 0 : childIndex) : key + ], + prevThenableState, + type, + props, + node + ); return; case REACT_PORTAL_TYPE: throw Error( @@ -3929,13 +3981,13 @@ function flushCompletedQueues(request, destination) { completedBoundaries.splice(0, i); var partialBoundaries = request.partialBoundaries; for (i = 0; i < partialBoundaries.length; i++) { - var boundary$13 = partialBoundaries[i]; + var boundary$15 = partialBoundaries[i]; a: { clientRenderedBoundaries = request; boundary = destination; clientRenderedBoundaries.renderState.boundaryResources = - boundary$13.resources; - var completedSegments = boundary$13.completedSegments; + boundary$15.resources; + var completedSegments = boundary$15.completedSegments; for ( resumableState$jscomp$1 = 0; resumableState$jscomp$1 < completedSegments.length; @@ -3945,7 +3997,7 @@ function flushCompletedQueues(request, destination) { !flushPartiallyCompletedSegment( clientRenderedBoundaries, boundary, - boundary$13, + boundary$15, completedSegments[resumableState$jscomp$1] ) ) { @@ -3957,7 +4009,7 @@ function flushCompletedQueues(request, destination) { completedSegments.splice(0, resumableState$jscomp$1); JSCompiler_inline_result = writeResourcesForBoundary( boundary, - boundary$13.resources, + boundary$15.resources, clientRenderedBoundaries.renderState ); } @@ -4017,8 +4069,8 @@ function abort(request, reason) { } null !== request.destination && flushCompletedQueues(request, request.destination); - } catch (error$15) { - logRecoverableError(request, error$15), fatalError(request, error$15); + } catch (error$17) { + logRecoverableError(request, error$17), fatalError(request, error$17); } } exports.abortStream = function (stream) { diff --git a/compiled/facebook-www/ReactTestRenderer-dev.modern.js b/compiled/facebook-www/ReactTestRenderer-dev.modern.js index 80fbe0aef63da..f8f4c8cd91315 100644 --- a/compiled/facebook-www/ReactTestRenderer-dev.modern.js +++ b/compiled/facebook-www/ReactTestRenderer-dev.modern.js @@ -24356,7 +24356,7 @@ function createFiberRoot( return root; } -var ReactVersion = "18.3.0-www-modern-fa0eb004"; +var ReactVersion = "18.3.0-www-modern-d9222bbe"; // Might add PROFILE later.