Skip to content

Commit 9148116

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 3bfa7bb commit 9148116

34 files changed

+1332
-1100
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3168e08f8389d258de9eb7c8d19b9d44a0f250f2
1+
3302d1f791f3f1cf4e8cf69bee70ce5dab1b8436
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3168e08f8389d258de9eb7c8d19b9d44a0f250f2
1+
3302d1f791f3f1cf4e8cf69bee70ce5dab1b8436

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1418,7 +1418,7 @@ __DEV__ &&
14181418
exports.useTransition = function () {
14191419
return resolveDispatcher().useTransition();
14201420
};
1421-
exports.version = "19.2.0-www-classic-3168e08f-20250903";
1421+
exports.version = "19.2.0-www-classic-3302d1f7-20250903";
14221422
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14231423
"function" ===
14241424
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1418,7 +1418,7 @@ __DEV__ &&
14181418
exports.useTransition = function () {
14191419
return resolveDispatcher().useTransition();
14201420
};
1421-
exports.version = "19.2.0-www-modern-3168e08f-20250903";
1421+
exports.version = "19.2.0-www-modern-3302d1f7-20250903";
14221422
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14231423
"function" ===
14241424
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,4 +600,4 @@ exports.useSyncExternalStore = function (
600600
exports.useTransition = function () {
601601
return ReactSharedInternals.H.useTransition();
602602
};
603-
exports.version = "19.2.0-www-classic-3168e08f-20250903";
603+
exports.version = "19.2.0-www-classic-3302d1f7-20250903";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,4 +600,4 @@ exports.useSyncExternalStore = function (
600600
exports.useTransition = function () {
601601
return ReactSharedInternals.H.useTransition();
602602
};
603-
exports.version = "19.2.0-www-modern-3168e08f-20250903";
603+
exports.version = "19.2.0-www-modern-3302d1f7-20250903";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ exports.useSyncExternalStore = function (
604604
exports.useTransition = function () {
605605
return ReactSharedInternals.H.useTransition();
606606
};
607-
exports.version = "19.2.0-www-classic-3168e08f-20250903";
607+
exports.version = "19.2.0-www-classic-3302d1f7-20250903";
608608
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
609609
"function" ===
610610
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ exports.useSyncExternalStore = function (
604604
exports.useTransition = function () {
605605
return ReactSharedInternals.H.useTransition();
606606
};
607-
exports.version = "19.2.0-www-modern-3168e08f-20250903";
607+
exports.version = "19.2.0-www-modern-3302d1f7-20250903";
608608
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
609609
"function" ===
610610
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,12 @@ __DEV__ &&
437437
case 32768:
438438
case 65536:
439439
case 131072:
440+
return lanes & 261888;
440441
case 262144:
441442
case 524288:
442443
case 1048576:
443444
case 2097152:
444-
return lanes & 4194048;
445+
return lanes & 3932160;
445446
case 4194304:
446447
case 8388608:
447448
case 16777216:
@@ -563,12 +564,6 @@ __DEV__ &&
563564
);
564565
}
565566
}
566-
function claimNextTransitionLane() {
567-
var lane = nextTransitionLane;
568-
nextTransitionLane <<= 1;
569-
0 === (nextTransitionLane & 4194048) && (nextTransitionLane = 256);
570-
return lane;
571-
}
572567
function claimNextRetryLane() {
573568
var lane = nextRetryLane;
574569
nextRetryLane <<= 1;
@@ -636,7 +631,7 @@ __DEV__ &&
636631
root.entanglements[spawnedLaneIndex] =
637632
root.entanglements[spawnedLaneIndex] |
638633
1073741824 |
639-
(entangledLanes & 4194090);
634+
(entangledLanes & 261930);
640635
}
641636
function markRootEntangled(root, entangledLanes) {
642637
var rootEntangledLanes = (root.entangledLanes |= entangledLanes);
@@ -3522,8 +3517,12 @@ __DEV__ &&
35223517
function requestTransitionLane() {
35233518
if (0 === currentEventTransitionLane) {
35243519
var actionScopeLane = currentEntangledLane;
3525-
currentEventTransitionLane =
3526-
0 !== actionScopeLane ? actionScopeLane : claimNextTransitionLane();
3520+
0 === actionScopeLane &&
3521+
((actionScopeLane = nextTransitionUpdateLane),
3522+
(nextTransitionUpdateLane <<= 1),
3523+
0 === (nextTransitionUpdateLane & 261888) &&
3524+
(nextTransitionUpdateLane = 256));
3525+
currentEventTransitionLane = actionScopeLane;
35273526
}
35283527
return currentEventTransitionLane;
35293528
}
@@ -6551,7 +6550,11 @@ __DEV__ &&
65516550
);
65526551
}
65536552
function mountDeferredValueImpl(hook, value, initialValue) {
6554-
if (void 0 === initialValue || 0 !== (renderLanes & 1073741824))
6553+
if (
6554+
void 0 === initialValue ||
6555+
(0 !== (renderLanes & 1073741824) &&
6556+
0 === (workInProgressRootRenderLanes & 261930))
6557+
)
65556558
return (hook.memoizedState = value);
65566559
hook.memoizedState = initialValue;
65576560
hook = requestDeferredLane();
@@ -6567,7 +6570,11 @@ __DEV__ &&
65676570
objectIs(hook, prevValue) || (didReceiveUpdate = !0),
65686571
hook
65696572
);
6570-
if (0 === (renderLanes & 42) || 0 !== (renderLanes & 1073741824))
6573+
if (
6574+
0 === (renderLanes & 42) ||
6575+
(0 !== (renderLanes & 1073741824) &&
6576+
0 === (workInProgressRootRenderLanes & 261930))
6577+
)
65716578
return (didReceiveUpdate = !0), (hook.memoizedState = value);
65726579
hook = requestDeferredLane();
65736580
currentlyRenderingFiber.lanes |= hook;
@@ -14442,13 +14449,18 @@ __DEV__ &&
1444214449
: currentUpdatePriority || DefaultEventPriority;
1444314450
}
1444414451
function requestDeferredLane() {
14445-
0 === workInProgressDeferredLane &&
14446-
(workInProgressDeferredLane =
14447-
0 !== (workInProgressRootRenderLanes & 536870912)
14448-
? 536870912
14449-
: claimNextTransitionLane());
14450-
var suspenseHandler = suspenseHandlerStackCursor.current;
14451-
null !== suspenseHandler && (suspenseHandler.flags |= 32);
14452+
if (0 === workInProgressDeferredLane)
14453+
if (0 !== (workInProgressRootRenderLanes & 536870912))
14454+
workInProgressDeferredLane = 536870912;
14455+
else {
14456+
var lane = nextTransitionDeferredLane;
14457+
nextTransitionDeferredLane <<= 1;
14458+
0 === (nextTransitionDeferredLane & 3932160) &&
14459+
(nextTransitionDeferredLane = 262144);
14460+
workInProgressDeferredLane = lane;
14461+
}
14462+
lane = suspenseHandlerStackCursor.current;
14463+
null !== lane && (lane.flags |= 32);
1445214464
return workInProgressDeferredLane;
1445314465
}
1445414466
function scheduleViewTransitionEvent(fiber, callback) {
@@ -16323,7 +16335,7 @@ __DEV__ &&
1632316335
suspendedCommitReason = root.pendingLanes;
1632416336
(enableInfiniteRenderLoopDetection &&
1632516337
(didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) ||
16326-
(0 !== (lanes & 4194090) && 0 !== (suspendedCommitReason & 42))
16338+
(0 !== (lanes & 261930) && 0 !== (suspendedCommitReason & 42))
1632716339
? ((nestedUpdateScheduled = !0),
1632816340
root === rootWithNestedUpdates
1632916341
? nestedUpdateCount++
@@ -17544,7 +17556,8 @@ __DEV__ &&
1754417556
clz32 = Math.clz32 ? Math.clz32 : clz32Fallback,
1754517557
log = Math.log,
1754617558
LN2 = Math.LN2,
17547-
nextTransitionLane = 256,
17559+
nextTransitionUpdateLane = 256,
17560+
nextTransitionDeferredLane = 262144,
1754817561
nextRetryLane = 4194304,
1754917562
DiscreteEventPriority = 2,
1755017563
ContinuousEventPriority = 8,
@@ -19695,10 +19708,10 @@ __DEV__ &&
1969519708
(function () {
1969619709
var internals = {
1969719710
bundleType: 1,
19698-
version: "19.2.0-www-classic-3168e08f-20250903",
19711+
version: "19.2.0-www-classic-3302d1f7-20250903",
1969919712
rendererPackageName: "react-art",
1970019713
currentDispatcherRef: ReactSharedInternals,
19701-
reconcilerVersion: "19.2.0-www-classic-3168e08f-20250903"
19714+
reconcilerVersion: "19.2.0-www-classic-3302d1f7-20250903"
1970219715
};
1970319716
internals.overrideHookState = overrideHookState;
1970419717
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -19732,7 +19745,7 @@ __DEV__ &&
1973219745
exports.Shape = Shape;
1973319746
exports.Surface = Surface;
1973419747
exports.Text = Text;
19735-
exports.version = "19.2.0-www-classic-3168e08f-20250903";
19748+
exports.version = "19.2.0-www-classic-3302d1f7-20250903";
1973619749
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1973719750
"function" ===
1973819751
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.modern.js

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,12 @@ __DEV__ &&
437437
case 32768:
438438
case 65536:
439439
case 131072:
440+
return lanes & 261888;
440441
case 262144:
441442
case 524288:
442443
case 1048576:
443444
case 2097152:
444-
return lanes & 4194048;
445+
return lanes & 3932160;
445446
case 4194304:
446447
case 8388608:
447448
case 16777216:
@@ -563,12 +564,6 @@ __DEV__ &&
563564
);
564565
}
565566
}
566-
function claimNextTransitionLane() {
567-
var lane = nextTransitionLane;
568-
nextTransitionLane <<= 1;
569-
0 === (nextTransitionLane & 4194048) && (nextTransitionLane = 256);
570-
return lane;
571-
}
572567
function claimNextRetryLane() {
573568
var lane = nextRetryLane;
574569
nextRetryLane <<= 1;
@@ -636,7 +631,7 @@ __DEV__ &&
636631
root.entanglements[spawnedLaneIndex] =
637632
root.entanglements[spawnedLaneIndex] |
638633
1073741824 |
639-
(entangledLanes & 4194090);
634+
(entangledLanes & 261930);
640635
}
641636
function markRootEntangled(root, entangledLanes) {
642637
var rootEntangledLanes = (root.entangledLanes |= entangledLanes);
@@ -3428,8 +3423,12 @@ __DEV__ &&
34283423
function requestTransitionLane() {
34293424
if (0 === currentEventTransitionLane) {
34303425
var actionScopeLane = currentEntangledLane;
3431-
currentEventTransitionLane =
3432-
0 !== actionScopeLane ? actionScopeLane : claimNextTransitionLane();
3426+
0 === actionScopeLane &&
3427+
((actionScopeLane = nextTransitionUpdateLane),
3428+
(nextTransitionUpdateLane <<= 1),
3429+
0 === (nextTransitionUpdateLane & 261888) &&
3430+
(nextTransitionUpdateLane = 256));
3431+
currentEventTransitionLane = actionScopeLane;
34333432
}
34343433
return currentEventTransitionLane;
34353434
}
@@ -6457,7 +6456,11 @@ __DEV__ &&
64576456
);
64586457
}
64596458
function mountDeferredValueImpl(hook, value, initialValue) {
6460-
if (void 0 === initialValue || 0 !== (renderLanes & 1073741824))
6459+
if (
6460+
void 0 === initialValue ||
6461+
(0 !== (renderLanes & 1073741824) &&
6462+
0 === (workInProgressRootRenderLanes & 261930))
6463+
)
64616464
return (hook.memoizedState = value);
64626465
hook.memoizedState = initialValue;
64636466
hook = requestDeferredLane();
@@ -6473,7 +6476,11 @@ __DEV__ &&
64736476
objectIs(hook, prevValue) || (didReceiveUpdate = !0),
64746477
hook
64756478
);
6476-
if (0 === (renderLanes & 42) || 0 !== (renderLanes & 1073741824))
6479+
if (
6480+
0 === (renderLanes & 42) ||
6481+
(0 !== (renderLanes & 1073741824) &&
6482+
0 === (workInProgressRootRenderLanes & 261930))
6483+
)
64776484
return (didReceiveUpdate = !0), (hook.memoizedState = value);
64786485
hook = requestDeferredLane();
64796486
currentlyRenderingFiber.lanes |= hook;
@@ -14260,13 +14267,18 @@ __DEV__ &&
1426014267
: currentUpdatePriority || DefaultEventPriority;
1426114268
}
1426214269
function requestDeferredLane() {
14263-
0 === workInProgressDeferredLane &&
14264-
(workInProgressDeferredLane =
14265-
0 !== (workInProgressRootRenderLanes & 536870912)
14266-
? 536870912
14267-
: claimNextTransitionLane());
14268-
var suspenseHandler = suspenseHandlerStackCursor.current;
14269-
null !== suspenseHandler && (suspenseHandler.flags |= 32);
14270+
if (0 === workInProgressDeferredLane)
14271+
if (0 !== (workInProgressRootRenderLanes & 536870912))
14272+
workInProgressDeferredLane = 536870912;
14273+
else {
14274+
var lane = nextTransitionDeferredLane;
14275+
nextTransitionDeferredLane <<= 1;
14276+
0 === (nextTransitionDeferredLane & 3932160) &&
14277+
(nextTransitionDeferredLane = 262144);
14278+
workInProgressDeferredLane = lane;
14279+
}
14280+
lane = suspenseHandlerStackCursor.current;
14281+
null !== lane && (lane.flags |= 32);
1427014282
return workInProgressDeferredLane;
1427114283
}
1427214284
function scheduleViewTransitionEvent(fiber, callback) {
@@ -16136,7 +16148,7 @@ __DEV__ &&
1613616148
suspendedCommitReason = root.pendingLanes;
1613716149
(enableInfiniteRenderLoopDetection &&
1613816150
(didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) ||
16139-
(0 !== (lanes & 4194090) && 0 !== (suspendedCommitReason & 42))
16151+
(0 !== (lanes & 261930) && 0 !== (suspendedCommitReason & 42))
1614016152
? ((nestedUpdateScheduled = !0),
1614116153
root === rootWithNestedUpdates
1614216154
? nestedUpdateCount++
@@ -17320,7 +17332,8 @@ __DEV__ &&
1732017332
clz32 = Math.clz32 ? Math.clz32 : clz32Fallback,
1732117333
log = Math.log,
1732217334
LN2 = Math.LN2,
17323-
nextTransitionLane = 256,
17335+
nextTransitionUpdateLane = 256,
17336+
nextTransitionDeferredLane = 262144,
1732417337
nextRetryLane = 4194304,
1732517338
DiscreteEventPriority = 2,
1732617339
ContinuousEventPriority = 8,
@@ -19466,10 +19479,10 @@ __DEV__ &&
1946619479
(function () {
1946719480
var internals = {
1946819481
bundleType: 1,
19469-
version: "19.2.0-www-modern-3168e08f-20250903",
19482+
version: "19.2.0-www-modern-3302d1f7-20250903",
1947019483
rendererPackageName: "react-art",
1947119484
currentDispatcherRef: ReactSharedInternals,
19472-
reconcilerVersion: "19.2.0-www-modern-3168e08f-20250903"
19485+
reconcilerVersion: "19.2.0-www-modern-3302d1f7-20250903"
1947319486
};
1947419487
internals.overrideHookState = overrideHookState;
1947519488
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -19503,7 +19516,7 @@ __DEV__ &&
1950319516
exports.Shape = Shape;
1950419517
exports.Surface = Surface;
1950519518
exports.Text = Text;
19506-
exports.version = "19.2.0-www-modern-3168e08f-20250903";
19519+
exports.version = "19.2.0-www-modern-3302d1f7-20250903";
1950719520
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1950819521
"function" ===
1950919522
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)