Skip to content

Commit 12c6a75

Browse files
committed
Fix: uDV skipped initial value if earlier transition suspended (#34376)
Fixes a bug in useDeferredValue's optional `initialValue` argument. In the regression case, if a new useDeferredValue hook is mounted while an earlier transition is suspended, the `initialValue` argument of the new hook was ignored. After the fix, the `initialValue` argument is correctly rendered during the initial mount, regardless of whether other transitions were suspended. The culprit was related to the mechanism we use to track whether a render is the result of a `useDeferredValue` hook: we assign the deferred lane a TransitionLane, then entangle that lane with the DeferredLane bit. During the subsequent render, we check for the presence of the DeferredLane bit to determine whether to switch to the final, canonical value. But because transition lanes can themselves become entangled with other transitions, the effect is that every entangled transition was being treated as if it were the result of a `useDeferredValue` hook, causing us to skip the initial value and go straight to the final one. The fix I've chosen is to reserve some subset of TransitionLanes to be used only for deferred work, instead of using entanglement. This is similar to how retries are already implemented. Originally I tried not to implement it this way because it means there are now slightly fewer lanes allocated for regular transitions, but I underestimated how similar deferred work is to retries; they end up having a lot of the same requirements. Eventually it may be possible to merge the two concepts. DiffTrain build for [3302d1f](3302d1f)
1 parent 0c939fc commit 12c6a75

24 files changed

+1027
-844
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-3168e08f-20250903
1+
19.2.0-native-fb-3302d1f7-20250903

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<<e16d4d0e56b0093108153a8e5c2fa6ec>>
10+
* @generated SignedSource<<56ac6a5f9e0a15495324372ea00e8858>>
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-3168e08f-20250903";
407+
exports.version = "19.2.0-native-fb-3302d1f7-20250903";
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<<5c28310e31f7b026d9838c06862fa435>>
10+
* @generated SignedSource<<73920b47ab48258a511372994a8afedd>>
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-3168e08f-20250903";
206+
exports.version = "19.2.0-native-fb-3302d1f7-20250903";

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<<5c28310e31f7b026d9838c06862fa435>>
10+
* @generated SignedSource<<73920b47ab48258a511372994a8afedd>>
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-3168e08f-20250903";
206+
exports.version = "19.2.0-native-fb-3302d1f7-20250903";

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

Lines changed: 155 additions & 144 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 & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<3281970e07dea5fb521ac7664dbecc34>>
10+
* @generated SignedSource<<145774a31461bc1e01f4c25468795fd9>>
1111
*/
1212

1313
/*
@@ -714,7 +714,8 @@ function clz32Fallback(x) {
714714
x >>>= 0;
715715
return 0 === x ? 32 : (31 - ((log(x) / LN2) | 0)) | 0;
716716
}
717-
var nextTransitionLane = 256,
717+
var nextTransitionUpdateLane = 256,
718+
nextTransitionDeferredLane = 262144,
718719
nextRetryLane = 4194304;
719720
function getHighestPriorityLanes(lanes) {
720721
var pendingSyncLanes = lanes & 42;
@@ -746,11 +747,12 @@ function getHighestPriorityLanes(lanes) {
746747
case 32768:
747748
case 65536:
748749
case 131072:
750+
return lanes & 261888;
749751
case 262144:
750752
case 524288:
751753
case 1048576:
752754
case 2097152:
753-
return lanes & 4194048;
755+
return lanes & 3932160;
754756
case 4194304:
755757
case 8388608:
756758
case 16777216:
@@ -859,12 +861,6 @@ function computeExpirationTime(lane, currentTime) {
859861
return -1;
860862
}
861863
}
862-
function claimNextTransitionLane() {
863-
var lane = nextTransitionLane;
864-
nextTransitionLane <<= 1;
865-
0 === (nextTransitionLane & 4194048) && (nextTransitionLane = 256);
866-
return lane;
867-
}
868864
function claimNextRetryLane() {
869865
var lane = nextRetryLane;
870866
nextRetryLane <<= 1;
@@ -937,7 +933,7 @@ function markSpawnedDeferredLane(root, spawnedLane, entangledLanes) {
937933
root.entanglements[spawnedLaneIndex] =
938934
root.entanglements[spawnedLaneIndex] |
939935
1073741824 |
940-
(entangledLanes & 4194090);
936+
(entangledLanes & 261930);
941937
}
942938
function markRootEntangled(root, entangledLanes) {
943939
var rootEntangledLanes = (root.entangledLanes |= entangledLanes);
@@ -5434,7 +5430,11 @@ function updateMemo(nextCreate, deps) {
54345430
return prevState;
54355431
}
54365432
function mountDeferredValueImpl(hook, value, initialValue) {
5437-
if (void 0 === initialValue || 0 !== (renderLanes & 1073741824))
5433+
if (
5434+
void 0 === initialValue ||
5435+
(0 !== (renderLanes & 1073741824) &&
5436+
0 === (workInProgressRootRenderLanes & 261930))
5437+
)
54385438
return (hook.memoizedState = value);
54395439
hook.memoizedState = initialValue;
54405440
hook = requestDeferredLane();
@@ -5450,7 +5450,11 @@ function updateDeferredValueImpl(hook, prevValue, value, initialValue) {
54505450
objectIs(hook, prevValue) || (didReceiveUpdate = !0),
54515451
hook
54525452
);
5453-
if (0 === (renderLanes & 42) || 0 !== (renderLanes & 1073741824))
5453+
if (
5454+
0 === (renderLanes & 42) ||
5455+
(0 !== (renderLanes & 1073741824) &&
5456+
0 === (workInProgressRootRenderLanes & 261930))
5457+
)
54545458
return (didReceiveUpdate = !0), (hook.memoizedState = value);
54555459
hook = requestDeferredLane();
54565460
currentlyRenderingFiber.lanes |= hook;
@@ -11447,13 +11451,16 @@ function requestUpdateLane(fiber) {
1144711451
: resolveUpdatePriority();
1144811452
}
1144911453
function requestDeferredLane() {
11450-
0 === workInProgressDeferredLane &&
11451-
(workInProgressDeferredLane =
11452-
0 === (workInProgressRootRenderLanes & 536870912) || isHydrating
11453-
? claimNextTransitionLane()
11454-
: 536870912);
11455-
var suspenseHandler = suspenseHandlerStackCursor.current;
11456-
null !== suspenseHandler && (suspenseHandler.flags |= 32);
11454+
if (0 === workInProgressDeferredLane)
11455+
if (0 === (workInProgressRootRenderLanes & 536870912) || isHydrating) {
11456+
var lane = nextTransitionDeferredLane;
11457+
nextTransitionDeferredLane <<= 1;
11458+
0 === (nextTransitionDeferredLane & 3932160) &&
11459+
(nextTransitionDeferredLane = 262144);
11460+
workInProgressDeferredLane = lane;
11461+
} else workInProgressDeferredLane = 536870912;
11462+
lane = suspenseHandlerStackCursor.current;
11463+
null !== lane && (lane.flags |= 32);
1145711464
return workInProgressDeferredLane;
1145811465
}
1145911466
function scheduleUpdateOnFiber(root, fiber, lane) {
@@ -12530,7 +12537,7 @@ function flushSpawnedWork() {
1253012537
0 !== (pendingEffectsLanes & 3) && 0 !== root.tag && flushPendingEffects();
1253112538
ensureRootIsScheduled(root);
1253212539
remainingLanes = root.pendingLanes;
12533-
0 !== (lanes & 4194090) && 0 !== (remainingLanes & 42)
12540+
0 !== (lanes & 261930) && 0 !== (remainingLanes & 42)
1253412541
? root === rootWithNestedUpdates
1253512542
? nestedUpdateCount++
1253612543
: ((nestedUpdateCount = 0), (rootWithNestedUpdates = root))
@@ -12981,8 +12988,12 @@ function scheduleImmediateRootScheduleTask() {
1298112988
function requestTransitionLane() {
1298212989
if (0 === currentEventTransitionLane) {
1298312990
var actionScopeLane = currentEntangledLane;
12984-
currentEventTransitionLane =
12985-
0 !== actionScopeLane ? actionScopeLane : claimNextTransitionLane();
12991+
0 === actionScopeLane &&
12992+
((actionScopeLane = nextTransitionUpdateLane),
12993+
(nextTransitionUpdateLane <<= 1),
12994+
0 === (nextTransitionUpdateLane & 261888) &&
12995+
(nextTransitionUpdateLane = 256));
12996+
currentEventTransitionLane = actionScopeLane;
1298612997
}
1298712998
return currentEventTransitionLane;
1298812999
}
@@ -13116,20 +13127,20 @@ function debounceScrollEnd(targetInst, nativeEvent, nativeEventTarget) {
1311613127
(nativeEventTarget[internalScrollTimer] = targetInst));
1311713128
}
1311813129
for (
13119-
var i$jscomp$inline_1646 = 0;
13120-
i$jscomp$inline_1646 < simpleEventPluginEvents.length;
13121-
i$jscomp$inline_1646++
13130+
var i$jscomp$inline_1651 = 0;
13131+
i$jscomp$inline_1651 < simpleEventPluginEvents.length;
13132+
i$jscomp$inline_1651++
1312213133
) {
13123-
var eventName$jscomp$inline_1647 =
13124-
simpleEventPluginEvents[i$jscomp$inline_1646],
13125-
domEventName$jscomp$inline_1648 =
13126-
eventName$jscomp$inline_1647.toLowerCase(),
13127-
capitalizedEvent$jscomp$inline_1649 =
13128-
eventName$jscomp$inline_1647[0].toUpperCase() +
13129-
eventName$jscomp$inline_1647.slice(1);
13134+
var eventName$jscomp$inline_1652 =
13135+
simpleEventPluginEvents[i$jscomp$inline_1651],
13136+
domEventName$jscomp$inline_1653 =
13137+
eventName$jscomp$inline_1652.toLowerCase(),
13138+
capitalizedEvent$jscomp$inline_1654 =
13139+
eventName$jscomp$inline_1652[0].toUpperCase() +
13140+
eventName$jscomp$inline_1652.slice(1);
1313013141
registerSimpleEvent(
13131-
domEventName$jscomp$inline_1648,
13132-
"on" + capitalizedEvent$jscomp$inline_1649
13142+
domEventName$jscomp$inline_1653,
13143+
"on" + capitalizedEvent$jscomp$inline_1654
1313313144
);
1313413145
}
1313513146
registerSimpleEvent(ANIMATION_END, "onAnimationEnd");
@@ -17375,16 +17386,16 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) {
1737517386
0 === i && attemptExplicitHydrationTarget(target);
1737617387
}
1737717388
};
17378-
var isomorphicReactPackageVersion$jscomp$inline_2052 = React.version;
17389+
var isomorphicReactPackageVersion$jscomp$inline_2057 = React.version;
1737917390
if (
17380-
"19.2.0-native-fb-3168e08f-20250903" !==
17381-
isomorphicReactPackageVersion$jscomp$inline_2052
17391+
"19.2.0-native-fb-3302d1f7-20250903" !==
17392+
isomorphicReactPackageVersion$jscomp$inline_2057
1738217393
)
1738317394
throw Error(
1738417395
formatProdErrorMessage(
1738517396
527,
17386-
isomorphicReactPackageVersion$jscomp$inline_2052,
17387-
"19.2.0-native-fb-3168e08f-20250903"
17397+
isomorphicReactPackageVersion$jscomp$inline_2057,
17398+
"19.2.0-native-fb-3302d1f7-20250903"
1738817399
)
1738917400
);
1739017401
ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
@@ -17404,24 +17415,24 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
1740417415
null === componentOrElement ? null : componentOrElement.stateNode;
1740517416
return componentOrElement;
1740617417
};
17407-
var internals$jscomp$inline_2625 = {
17418+
var internals$jscomp$inline_2630 = {
1740817419
bundleType: 0,
17409-
version: "19.2.0-native-fb-3168e08f-20250903",
17420+
version: "19.2.0-native-fb-3302d1f7-20250903",
1741017421
rendererPackageName: "react-dom",
1741117422
currentDispatcherRef: ReactSharedInternals,
17412-
reconcilerVersion: "19.2.0-native-fb-3168e08f-20250903"
17423+
reconcilerVersion: "19.2.0-native-fb-3302d1f7-20250903"
1741317424
};
1741417425
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
17415-
var hook$jscomp$inline_2626 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
17426+
var hook$jscomp$inline_2631 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
1741617427
if (
17417-
!hook$jscomp$inline_2626.isDisabled &&
17418-
hook$jscomp$inline_2626.supportsFiber
17428+
!hook$jscomp$inline_2631.isDisabled &&
17429+
hook$jscomp$inline_2631.supportsFiber
1741917430
)
1742017431
try {
17421-
(rendererID = hook$jscomp$inline_2626.inject(
17422-
internals$jscomp$inline_2625
17432+
(rendererID = hook$jscomp$inline_2631.inject(
17433+
internals$jscomp$inline_2630
1742317434
)),
17424-
(injectedHook = hook$jscomp$inline_2626);
17435+
(injectedHook = hook$jscomp$inline_2631);
1742517436
} catch (err) {}
1742617437
}
1742717438
exports.createRoot = function (container, options) {
@@ -17516,4 +17527,4 @@ exports.hydrateRoot = function (container, initialChildren, options) {
1751617527
listenToAllSupportedEvents(container);
1751717528
return new ReactDOMHydrationRoot(initialChildren);
1751817529
};
17519-
exports.version = "19.2.0-native-fb-3168e08f-20250903";
17530+
exports.version = "19.2.0-native-fb-3302d1f7-20250903";

0 commit comments

Comments
 (0)