Skip to content

Commit 800cc35

Browse files
committed
Fix: Synchronous popstate transitions (#30759)
This is a refactor of the fix in #27505. When a transition update is scheduled by a popstate event, (i.e. a back/ forward navigation) we attempt to render it synchronously even though it's a transition, since it's likely the previous page's data is cached. In #27505, I changed the implementation so that it only "upgrades" the priority of the transition for a single attempt. If the attempt suspends, say because the data is not cached after all, from then on it should be treated as a normal transition. But it turns out #27505 did not work as intended, because it relied on marking the root with pending synchronous work (root.pendingLanes), which was never cleared until the popstate update completed. The test scenarios I wrote accidentally worked for a different reason related to suspending the work loop, which I'm currently in the middle of refactoring. DiffTrain build for [ee7f675](ee7f675)
1 parent d1fee4a commit 800cc35

34 files changed

+3967
-3683
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1d989965a6aac11d71ecf28030796f5475a86642
1+
ee7f6757c446c4e79ecc7e2bc22b8c9b712834b7
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1d989965a6aac11d71ecf28030796f5475a86642
1+
ee7f6757c446c4e79ecc7e2bc22b8c9b712834b7

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2001,7 +2001,7 @@ __DEV__ &&
20012001
exports.useTransition = function () {
20022002
return resolveDispatcher().useTransition();
20032003
};
2004-
exports.version = "19.0.0-www-classic-1d989965-20240821";
2004+
exports.version = "19.0.0-www-classic-ee7f6757-20240823";
20052005
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
20062006
"function" ===
20072007
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
@@ -1981,7 +1981,7 @@ __DEV__ &&
19811981
exports.useTransition = function () {
19821982
return resolveDispatcher().useTransition();
19831983
};
1984-
exports.version = "19.0.0-www-modern-1d989965-20240821";
1984+
exports.version = "19.0.0-www-modern-ee7f6757-20240823";
19851985
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19861986
"function" ===
19871987
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
@@ -665,4 +665,4 @@ exports.useSyncExternalStore = function (
665665
exports.useTransition = function () {
666666
return ReactSharedInternals.H.useTransition();
667667
};
668-
exports.version = "19.0.0-www-classic-1d989965-20240821";
668+
exports.version = "19.0.0-www-classic-ee7f6757-20240823";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,4 +665,4 @@ exports.useSyncExternalStore = function (
665665
exports.useTransition = function () {
666666
return ReactSharedInternals.H.useTransition();
667667
};
668-
exports.version = "19.0.0-www-modern-1d989965-20240821";
668+
exports.version = "19.0.0-www-modern-ee7f6757-20240823";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ exports.useSyncExternalStore = function (
669669
exports.useTransition = function () {
670670
return ReactSharedInternals.H.useTransition();
671671
};
672-
exports.version = "19.0.0-www-classic-1d989965-20240821";
672+
exports.version = "19.0.0-www-classic-ee7f6757-20240823";
673673
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
674674
"function" ===
675675
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
@@ -669,7 +669,7 @@ exports.useSyncExternalStore = function (
669669
exports.useTransition = function () {
670670
return ReactSharedInternals.H.useTransition();
671671
};
672-
exports.version = "19.0.0-www-modern-1d989965-20240821";
672+
exports.version = "19.0.0-www-modern-ee7f6757-20240823";
673673
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
674674
"function" ===
675675
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,28 +2057,41 @@ __DEV__ &&
20572057
0 === root.tag &&
20582058
(ReactSharedInternals.didScheduleLegacyUpdate = !0);
20592059
}
2060-
function flushSyncWorkAcrossRoots_impl(onlyLegacy) {
2060+
function flushSyncWorkAcrossRoots_impl(syncTransitionLanes, onlyLegacy) {
20612061
if (!isFlushingWork && mightHavePendingSyncWork) {
20622062
isFlushingWork = !0;
20632063
do {
20642064
var didPerformSomeWork = !1;
20652065
for (var root = firstScheduledRoot; null !== root; ) {
2066-
if (!onlyLegacy || (!disableLegacyMode && 0 === root.tag)) {
2067-
var workInProgressRootRenderLanes$jscomp$0 =
2068-
workInProgressRootRenderLanes;
2069-
workInProgressRootRenderLanes$jscomp$0 = getNextLanes(
2070-
root,
2071-
root === workInProgressRoot
2072-
? workInProgressRootRenderLanes$jscomp$0
2073-
: 0
2074-
);
2075-
0 !== (workInProgressRootRenderLanes$jscomp$0 & 3) &&
2076-
((didPerformSomeWork = !0),
2077-
performSyncWorkOnRoot(
2078-
root,
2079-
workInProgressRootRenderLanes$jscomp$0
2080-
));
2081-
}
2066+
if (!onlyLegacy || (!disableLegacyMode && 0 === root.tag))
2067+
if (0 !== syncTransitionLanes) {
2068+
var pendingLanes = root.pendingLanes;
2069+
if (0 === pendingLanes) var nextLanes = 0;
2070+
else {
2071+
var suspendedLanes = root.suspendedLanes,
2072+
pingedLanes = root.pingedLanes;
2073+
nextLanes =
2074+
(1 << (31 - clz32(42 | syncTransitionLanes) + 1)) - 1;
2075+
nextLanes &= pendingLanes & ~(suspendedLanes & ~pingedLanes);
2076+
nextLanes =
2077+
nextLanes & 201326677
2078+
? (nextLanes & 201326677) | 1
2079+
: nextLanes
2080+
? nextLanes | 2
2081+
: 0;
2082+
}
2083+
0 !== nextLanes &&
2084+
((didPerformSomeWork = !0),
2085+
performSyncWorkOnRoot(root, nextLanes));
2086+
} else
2087+
(nextLanes = workInProgressRootRenderLanes),
2088+
(nextLanes = getNextLanes(
2089+
root,
2090+
root === workInProgressRoot ? nextLanes : 0
2091+
)),
2092+
0 !== (nextLanes & 3) &&
2093+
((didPerformSomeWork = !0),
2094+
performSyncWorkOnRoot(root, nextLanes));
20822095
root = root.next;
20832096
}
20842097
} while (didPerformSomeWork);
@@ -2090,6 +2103,7 @@ __DEV__ &&
20902103
didScheduleMicrotask_act =
20912104
didScheduleMicrotask =
20922105
!1;
2106+
0 !== currentEventTransitionLane && (currentEventTransitionLane = 0);
20932107
for (
20942108
var currentTime = now$1(), prev = null, root = firstScheduledRoot;
20952109
null !== root;
@@ -2105,8 +2119,7 @@ __DEV__ &&
21052119
0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0));
21062120
root = next;
21072121
}
2108-
currentEventTransitionLane = 0;
2109-
flushSyncWorkAcrossRoots_impl(!1);
2122+
flushSyncWorkAcrossRoots_impl(0, !1);
21102123
}
21112124
function scheduleTaskForRootDuringMicrotask(root, currentTime) {
21122125
var pendingLanes = root.pendingLanes,
@@ -12318,7 +12331,7 @@ __DEV__ &&
1231812331
0 !== (fiber.mode & 1) ||
1231912332
ReactSharedInternals.isBatchingLegacy ||
1232012333
((workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS),
12321-
disableLegacyMode || flushSyncWorkAcrossRoots_impl(!0));
12334+
disableLegacyMode || flushSyncWorkAcrossRoots_impl(0, !0));
1232212335
}
1232312336
}
1232412337
function performConcurrentWorkOnRoot(root, didTimeout) {
@@ -12628,7 +12641,7 @@ __DEV__ &&
1262812641
}
1262912642
function flushSyncWork() {
1263012643
return (executionContext & (RenderContext | CommitContext)) === NoContext
12631-
? (flushSyncWorkAcrossRoots_impl(!1), !1)
12644+
? (flushSyncWorkAcrossRoots_impl(0, !1), !1)
1263212645
: !0;
1263312646
}
1263412647
function resetWorkInProgressStack() {
@@ -13370,7 +13383,7 @@ __DEV__ &&
1337013383
? nestedUpdateCount++
1337113384
: ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)))
1337213385
: (nestedUpdateCount = 0);
13373-
flushSyncWorkAcrossRoots_impl(!1);
13386+
flushSyncWorkAcrossRoots_impl(0, !1);
1337413387
enableDebugTracing && enableDebugTracing && groupEnd();
1337513388
enableSchedulingProfiler && markCommitStopped();
1337613389
return null;
@@ -13470,7 +13483,7 @@ __DEV__ &&
1347013483
injectedProfilingHooks.markPassiveEffectsStopped();
1347113484
commitDoubleInvokeEffectsInDEV(root, !0);
1347213485
executionContext = prevExecutionContext;
13473-
flushSyncWorkAcrossRoots_impl(!1);
13486+
flushSyncWorkAcrossRoots_impl(0, !1);
1347413487
if (enableTransitionTracing) {
1347513488
var prevPendingTransitionCallbacks = currentPendingTransitionCallbacks,
1347613489
prevRootTransitionCallbacks = root.transitionCallbacks,
@@ -16776,11 +16789,11 @@ __DEV__ &&
1677616789
(function () {
1677716790
var internals = {
1677816791
bundleType: 1,
16779-
version: "19.0.0-www-classic-1d989965-20240821",
16792+
version: "19.0.0-www-classic-ee7f6757-20240823",
1678016793
rendererPackageName: "react-art",
1678116794
currentDispatcherRef: ReactSharedInternals,
1678216795
findFiberByHostInstance: getInstanceFromNode,
16783-
reconcilerVersion: "19.0.0-www-classic-1d989965-20240821"
16796+
reconcilerVersion: "19.0.0-www-classic-ee7f6757-20240823"
1678416797
};
1678516798
internals.overrideHookState = overrideHookState;
1678616799
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16814,7 +16827,7 @@ __DEV__ &&
1681416827
exports.Shape = Shape;
1681516828
exports.Surface = Surface;
1681616829
exports.Text = Text;
16817-
exports.version = "19.0.0-www-classic-1d989965-20240821";
16830+
exports.version = "19.0.0-www-classic-ee7f6757-20240823";
1681816831
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1681916832
"function" ===
1682016833
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1942,28 +1942,41 @@ __DEV__ &&
19421942
enableDeferRootSchedulingToMicrotask ||
19431943
scheduleTaskForRootDuringMicrotask(root, now$1());
19441944
}
1945-
function flushSyncWorkAcrossRoots_impl(onlyLegacy) {
1945+
function flushSyncWorkAcrossRoots_impl(syncTransitionLanes, onlyLegacy) {
19461946
if (!isFlushingWork && mightHavePendingSyncWork) {
19471947
isFlushingWork = !0;
19481948
do {
19491949
var didPerformSomeWork = !1;
19501950
for (var root = firstScheduledRoot; null !== root; ) {
1951-
if (!onlyLegacy) {
1952-
var workInProgressRootRenderLanes$jscomp$0 =
1953-
workInProgressRootRenderLanes;
1954-
workInProgressRootRenderLanes$jscomp$0 = getNextLanes(
1955-
root,
1956-
root === workInProgressRoot
1957-
? workInProgressRootRenderLanes$jscomp$0
1958-
: 0
1959-
);
1960-
0 !== (workInProgressRootRenderLanes$jscomp$0 & 3) &&
1961-
((didPerformSomeWork = !0),
1962-
performSyncWorkOnRoot(
1963-
root,
1964-
workInProgressRootRenderLanes$jscomp$0
1965-
));
1966-
}
1951+
if (!onlyLegacy)
1952+
if (0 !== syncTransitionLanes) {
1953+
var pendingLanes = root.pendingLanes;
1954+
if (0 === pendingLanes) var nextLanes = 0;
1955+
else {
1956+
var suspendedLanes = root.suspendedLanes,
1957+
pingedLanes = root.pingedLanes;
1958+
nextLanes =
1959+
(1 << (31 - clz32(42 | syncTransitionLanes) + 1)) - 1;
1960+
nextLanes &= pendingLanes & ~(suspendedLanes & ~pingedLanes);
1961+
nextLanes =
1962+
nextLanes & 201326677
1963+
? (nextLanes & 201326677) | 1
1964+
: nextLanes
1965+
? nextLanes | 2
1966+
: 0;
1967+
}
1968+
0 !== nextLanes &&
1969+
((didPerformSomeWork = !0),
1970+
performSyncWorkOnRoot(root, nextLanes));
1971+
} else
1972+
(nextLanes = workInProgressRootRenderLanes),
1973+
(nextLanes = getNextLanes(
1974+
root,
1975+
root === workInProgressRoot ? nextLanes : 0
1976+
)),
1977+
0 !== (nextLanes & 3) &&
1978+
((didPerformSomeWork = !0),
1979+
performSyncWorkOnRoot(root, nextLanes));
19671980
root = root.next;
19681981
}
19691982
} while (didPerformSomeWork);
@@ -1975,6 +1988,7 @@ __DEV__ &&
19751988
didScheduleMicrotask_act =
19761989
didScheduleMicrotask =
19771990
!1;
1991+
0 !== currentEventTransitionLane && (currentEventTransitionLane = 0);
19781992
for (
19791993
var currentTime = now$1(), prev = null, root = firstScheduledRoot;
19801994
null !== root;
@@ -1990,8 +2004,7 @@ __DEV__ &&
19902004
0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0));
19912005
root = next;
19922006
}
1993-
currentEventTransitionLane = 0;
1994-
flushSyncWorkAcrossRoots_impl(!1);
2007+
flushSyncWorkAcrossRoots_impl(0, !1);
19952008
}
19962009
function scheduleTaskForRootDuringMicrotask(root, currentTime) {
19972010
var pendingLanes = root.pendingLanes,
@@ -12144,7 +12157,7 @@ __DEV__ &&
1214412157
}
1214512158
function flushSyncWork() {
1214612159
return (executionContext & (RenderContext | CommitContext)) === NoContext
12147-
? (flushSyncWorkAcrossRoots_impl(!1), !1)
12160+
? (flushSyncWorkAcrossRoots_impl(0, !1), !1)
1214812161
: !0;
1214912162
}
1215012163
function resetWorkInProgressStack() {
@@ -12880,7 +12893,7 @@ __DEV__ &&
1288012893
? nestedUpdateCount++
1288112894
: ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)))
1288212895
: (nestedUpdateCount = 0);
12883-
flushSyncWorkAcrossRoots_impl(!1);
12896+
flushSyncWorkAcrossRoots_impl(0, !1);
1288412897
enableDebugTracing && enableDebugTracing && groupEnd();
1288512898
enableSchedulingProfiler && markCommitStopped();
1288612899
return null;
@@ -12980,7 +12993,7 @@ __DEV__ &&
1298012993
injectedProfilingHooks.markPassiveEffectsStopped();
1298112994
commitDoubleInvokeEffectsInDEV(root);
1298212995
executionContext = prevExecutionContext;
12983-
flushSyncWorkAcrossRoots_impl(!1);
12996+
flushSyncWorkAcrossRoots_impl(0, !1);
1298412997
if (enableTransitionTracing) {
1298512998
var prevPendingTransitionCallbacks = currentPendingTransitionCallbacks,
1298612999
prevRootTransitionCallbacks = root.transitionCallbacks,
@@ -16189,11 +16202,11 @@ __DEV__ &&
1618916202
(function () {
1619016203
var internals = {
1619116204
bundleType: 1,
16192-
version: "19.0.0-www-modern-1d989965-20240821",
16205+
version: "19.0.0-www-modern-ee7f6757-20240823",
1619316206
rendererPackageName: "react-art",
1619416207
currentDispatcherRef: ReactSharedInternals,
1619516208
findFiberByHostInstance: getInstanceFromNode,
16196-
reconcilerVersion: "19.0.0-www-modern-1d989965-20240821"
16209+
reconcilerVersion: "19.0.0-www-modern-ee7f6757-20240823"
1619716210
};
1619816211
internals.overrideHookState = overrideHookState;
1619916212
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16227,7 +16240,7 @@ __DEV__ &&
1622716240
exports.Shape = Shape;
1622816241
exports.Surface = Surface;
1622916242
exports.Text = Text;
16230-
exports.version = "19.0.0-www-modern-1d989965-20240821";
16243+
exports.version = "19.0.0-www-modern-ee7f6757-20240823";
1623116244
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1623216245
"function" ===
1623316246
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)