Skip to content

Commit 07f9b02

Browse files
committed
[Fiber] Fix hydration of useId in SuspenseList (#33491)
Includes #31412. The issue is that `pushTreeFork` stores some global state when reconcile children. This gets popped by `popTreeContext` in `completeWork`. Normally `completeWork` returns its own `Fiber` again if it wants to do a second pass which will call `pushTreeFork` again in the next pass. However, `SuspenseList` doesn't return itself, it returns the next child to work on. The fix is to keep track of the count and push it again it when we return the next child to attempt. There are still some outstanding issues with hydration. Like the backwards test still has the wrong behavior in it because it hydrates backwards and so it picks up the DOM nodes in reverse order. `tail="hidden"` also doesn't work correctly. There's also another issue with `useId` and `AsyncIterable` in SuspenseList when there's an unknown number of children. We don't support those showing one at a time yet though so it's not an issue yet. To fix it we need to add variable total count to the `useId` algorithm. E.g. by falling back to varint encoding. --------- Co-authored-by: Rick Hanlon <[email protected]> Co-authored-by: Ricky <[email protected]> DiffTrain build for [c38e268](c38e268)
1 parent 8b8eae7 commit 07f9b02

24 files changed

+779
-609
lines changed

compiled-rn/VERSION_NATIVE_FB

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19.2.0-native-fb-4df098c4-20250609
1+
19.2.0-native-fb-c38e2689-20250609

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOM-dev.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<da75df0cd587f7e80d7be0034ae4ad1a>>
10+
* @generated SignedSource<<f660a097df86c854e2c5ddc26ec6b5d8>>
1111
*/
1212

1313
"use strict";
@@ -404,5 +404,5 @@ __DEV__ &&
404404
exports.useFormStatus = function () {
405405
return resolveDispatcher().useHostTransitionStatus();
406406
};
407-
exports.version = "19.2.0-native-fb-4df098c4-20250609";
407+
exports.version = "19.2.0-native-fb-c38e2689-20250609";
408408
})();

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOM-prod.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<46bffb43a8819cf9fa4a1cef9499b2e5>>
10+
* @generated SignedSource<<62f37a389aea3724c49e6baca478992f>>
1111
*/
1212

1313
"use strict";
@@ -203,4 +203,4 @@ exports.useFormState = function (action, initialState, permalink) {
203203
exports.useFormStatus = function () {
204204
return ReactSharedInternals.H.useHostTransitionStatus();
205205
};
206-
exports.version = "19.2.0-native-fb-4df098c4-20250609";
206+
exports.version = "19.2.0-native-fb-c38e2689-20250609";

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOM-profiling.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<46bffb43a8819cf9fa4a1cef9499b2e5>>
10+
* @generated SignedSource<<62f37a389aea3724c49e6baca478992f>>
1111
*/
1212

1313
"use strict";
@@ -203,4 +203,4 @@ exports.useFormState = function (action, initialState, permalink) {
203203
exports.useFormStatus = function () {
204204
return ReactSharedInternals.H.useHostTransitionStatus();
205205
};
206-
exports.version = "19.2.0-native-fb-4df098c4-20250609";
206+
exports.version = "19.2.0-native-fb-c38e2689-20250609";

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOMClient-dev.js

Lines changed: 184 additions & 170 deletions
Large diffs are not rendered by default.

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOMClient-prod.js

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<462efb9d1de3f47dfd794819a5a7c09c>>
10+
* @generated SignedSource<<8170fbccb360ffc71c537e172809ef3d>>
1111
*/
1212

1313
/*
@@ -7390,7 +7390,8 @@ function initSuspenseListRenderState(
73907390
isBackwards,
73917391
tail,
73927392
lastContentRow,
7393-
tailMode
7393+
tailMode,
7394+
treeForkCount
73947395
) {
73957396
var renderState = workInProgress.memoizedState;
73967397
null === renderState
@@ -7400,14 +7401,16 @@ function initSuspenseListRenderState(
74007401
renderingStartTime: 0,
74017402
last: lastContentRow,
74027403
tail: tail,
7403-
tailMode: tailMode
7404+
tailMode: tailMode,
7405+
treeForkCount: treeForkCount
74047406
})
74057407
: ((renderState.isBackwards = isBackwards),
74067408
(renderState.rendering = null),
74077409
(renderState.renderingStartTime = 0),
74087410
(renderState.last = lastContentRow),
74097411
(renderState.tail = tail),
7410-
(renderState.tailMode = tailMode));
7412+
(renderState.tailMode = tailMode),
7413+
(renderState.treeForkCount = treeForkCount));
74117414
}
74127415
function updateSuspenseListComponent(current, workInProgress, renderLanes) {
74137416
var nextProps = workInProgress.pendingProps,
@@ -7422,6 +7425,7 @@ function updateSuspenseListComponent(current, workInProgress, renderLanes) {
74227425
: (suspenseContext &= 1);
74237426
push(suspenseStackCursor, suspenseContext);
74247427
reconcileChildren(current, workInProgress, nextProps, renderLanes);
7428+
nextProps = isHydrating ? treeForkCount : 0;
74257429
if (!shouldForceFallback && null !== current && 0 !== (current.flags & 128))
74267430
a: for (current = workInProgress.child; null !== current; ) {
74277431
if (13 === current.tag)
@@ -7464,7 +7468,8 @@ function updateSuspenseListComponent(current, workInProgress, renderLanes) {
74647468
!1,
74657469
revealOrder,
74667470
renderLanes,
7467-
tailMode
7471+
tailMode,
7472+
nextProps
74687473
);
74697474
break;
74707475
case "backwards":
@@ -7487,11 +7492,19 @@ function updateSuspenseListComponent(current, workInProgress, renderLanes) {
74877492
!0,
74887493
renderLanes,
74897494
null,
7490-
tailMode
7495+
tailMode,
7496+
nextProps
74917497
);
74927498
break;
74937499
case "together":
7494-
initSuspenseListRenderState(workInProgress, !1, null, null, void 0);
7500+
initSuspenseListRenderState(
7501+
workInProgress,
7502+
!1,
7503+
null,
7504+
null,
7505+
void 0,
7506+
nextProps
7507+
);
74957508
break;
74967509
default:
74977510
workInProgress.memoizedState = null;
@@ -8762,12 +8775,12 @@ function completeWork(current, workInProgress, renderLanes) {
87628775
);
87638776
case 19:
87648777
pop(suspenseStackCursor);
8765-
type = workInProgress.memoizedState;
8766-
if (null === type) return bubbleProperties(workInProgress), null;
8767-
newProps = 0 !== (workInProgress.flags & 128);
8768-
nextResource = type.rendering;
8778+
newProps = workInProgress.memoizedState;
8779+
if (null === newProps) return bubbleProperties(workInProgress), null;
8780+
type = 0 !== (workInProgress.flags & 128);
8781+
nextResource = newProps.rendering;
87698782
if (null === nextResource)
8770-
if (newProps) cutOffTailIfNeeded(type, !1);
8783+
if (type) cutOffTailIfNeeded(newProps, !1);
87718784
else {
87728785
if (
87738786
0 !== workInProgressRootExitStatus ||
@@ -8777,7 +8790,7 @@ function completeWork(current, workInProgress, renderLanes) {
87778790
nextResource = findFirstSuspended(current);
87788791
if (null !== nextResource) {
87798792
workInProgress.flags |= 128;
8780-
cutOffTailIfNeeded(type, !1);
8793+
cutOffTailIfNeeded(newProps, !1);
87818794
current = nextResource.updateQueue;
87828795
workInProgress.updateQueue = current;
87838796
scheduleRetryEffect(workInProgress, current);
@@ -8790,62 +8803,68 @@ function completeWork(current, workInProgress, renderLanes) {
87908803
suspenseStackCursor,
87918804
(suspenseStackCursor.current & 1) | 2
87928805
);
8806+
isHydrating &&
8807+
pushTreeFork(workInProgress, newProps.treeForkCount);
87938808
return workInProgress.child;
87948809
}
87958810
current = current.sibling;
87968811
}
8797-
null !== type.tail &&
8812+
null !== newProps.tail &&
87988813
now() > workInProgressRootRenderTargetTime &&
87998814
((workInProgress.flags |= 128),
8800-
(newProps = !0),
8801-
cutOffTailIfNeeded(type, !1),
8815+
(type = !0),
8816+
cutOffTailIfNeeded(newProps, !1),
88028817
(workInProgress.lanes = 4194304));
88038818
}
88048819
else {
8805-
if (!newProps)
8820+
if (!type)
88068821
if (
88078822
((current = findFirstSuspended(nextResource)), null !== current)
88088823
) {
88098824
if (
88108825
((workInProgress.flags |= 128),
8811-
(newProps = !0),
8826+
(type = !0),
88128827
(current = current.updateQueue),
88138828
(workInProgress.updateQueue = current),
88148829
scheduleRetryEffect(workInProgress, current),
8815-
cutOffTailIfNeeded(type, !0),
8816-
null === type.tail &&
8817-
"hidden" === type.tailMode &&
8830+
cutOffTailIfNeeded(newProps, !0),
8831+
null === newProps.tail &&
8832+
"hidden" === newProps.tailMode &&
88188833
!nextResource.alternate &&
88198834
!isHydrating)
88208835
)
88218836
return bubbleProperties(workInProgress), null;
88228837
} else
8823-
2 * now() - type.renderingStartTime >
8838+
2 * now() - newProps.renderingStartTime >
88248839
workInProgressRootRenderTargetTime &&
88258840
536870912 !== renderLanes &&
88268841
((workInProgress.flags |= 128),
8827-
(newProps = !0),
8828-
cutOffTailIfNeeded(type, !1),
8842+
(type = !0),
8843+
cutOffTailIfNeeded(newProps, !1),
88298844
(workInProgress.lanes = 4194304));
8830-
type.isBackwards
8845+
newProps.isBackwards
88318846
? ((nextResource.sibling = workInProgress.child),
88328847
(workInProgress.child = nextResource))
8833-
: ((current = type.last),
8848+
: ((current = newProps.last),
88348849
null !== current
88358850
? (current.sibling = nextResource)
88368851
: (workInProgress.child = nextResource),
8837-
(type.last = nextResource));
8852+
(newProps.last = nextResource));
88388853
}
8839-
if (null !== type.tail)
8854+
if (null !== newProps.tail)
88408855
return (
8841-
(workInProgress = type.tail),
8842-
(type.rendering = workInProgress),
8843-
(type.tail = workInProgress.sibling),
8844-
(type.renderingStartTime = now()),
8845-
(workInProgress.sibling = null),
8846-
(current = suspenseStackCursor.current),
8847-
push(suspenseStackCursor, newProps ? (current & 1) | 2 : current & 1),
8848-
workInProgress
8856+
(current = newProps.tail),
8857+
(newProps.rendering = current),
8858+
(newProps.tail = current.sibling),
8859+
(newProps.renderingStartTime = now()),
8860+
(current.sibling = null),
8861+
(renderLanes = suspenseStackCursor.current),
8862+
push(
8863+
suspenseStackCursor,
8864+
type ? (renderLanes & 1) | 2 : renderLanes & 1
8865+
),
8866+
isHydrating && pushTreeFork(workInProgress, newProps.treeForkCount),
8867+
current
88498868
);
88508869
bubbleProperties(workInProgress);
88518870
return null;
@@ -17101,14 +17120,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) {
1710117120
};
1710217121
var isomorphicReactPackageVersion$jscomp$inline_2017 = React.version;
1710317122
if (
17104-
"19.2.0-native-fb-4df098c4-20250609" !==
17123+
"19.2.0-native-fb-c38e2689-20250609" !==
1710517124
isomorphicReactPackageVersion$jscomp$inline_2017
1710617125
)
1710717126
throw Error(
1710817127
formatProdErrorMessage(
1710917128
527,
1711017129
isomorphicReactPackageVersion$jscomp$inline_2017,
17111-
"19.2.0-native-fb-4df098c4-20250609"
17130+
"19.2.0-native-fb-c38e2689-20250609"
1711217131
)
1711317132
);
1711417133
ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
@@ -17130,10 +17149,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
1713017149
};
1713117150
var internals$jscomp$inline_2536 = {
1713217151
bundleType: 0,
17133-
version: "19.2.0-native-fb-4df098c4-20250609",
17152+
version: "19.2.0-native-fb-c38e2689-20250609",
1713417153
rendererPackageName: "react-dom",
1713517154
currentDispatcherRef: ReactSharedInternals,
17136-
reconcilerVersion: "19.2.0-native-fb-4df098c4-20250609"
17155+
reconcilerVersion: "19.2.0-native-fb-c38e2689-20250609"
1713717156
};
1713817157
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1713917158
var hook$jscomp$inline_2537 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -17231,4 +17250,4 @@ exports.hydrateRoot = function (container, initialChildren, options) {
1723117250
listenToAllSupportedEvents(container);
1723217251
return new ReactDOMHydrationRoot(initialChildren);
1723317252
};
17234-
exports.version = "19.2.0-native-fb-4df098c4-20250609";
17253+
exports.version = "19.2.0-native-fb-c38e2689-20250609";

0 commit comments

Comments
 (0)