Skip to content

Commit cda4f89

Browse files
committed
Synchronously flush the transition lane scheduled in a popstate event (#26025)
<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory. Before submitting a pull request, please make sure the following is done: 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. 6. If you need a debugger, run `yarn debug-test --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). 10. If you haven't already, complete the CLA. Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html --> ## Summary Browsers restore state like forms and scroll position right after the popstate event. To make sure the page work as expected on back or forward button, we need to flush transitions scheduled in a popstate synchronously, and only yields if it suspends. This PR adds a new HostConfig method to check if `window.event === 'popstate'`, and `scheduleMicrotask` if a transition is scheduled in a `PopStateEvent`. ## How did you test this change? yarn test DiffTrain build for [d121c67](d121c67)
1 parent 94c515f commit cda4f89

18 files changed

+504
-336
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7b0642bb989ec659c6c9891ea16daa0420caab4d
1+
d121c67004a2e6b0bb5d341843663ef213f64863

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-modern-50a23993";
30+
var ReactVersion = "18.3.0-www-modern-40ddfb33";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

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

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-classic-4e76503d";
72+
var ReactVersion = "18.3.0-www-classic-09c9197a";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -2836,6 +2836,9 @@ function shouldSetTextContent(type, props) {
28362836
}
28372837
function getCurrentEventPriority() {
28382838
return DefaultEventPriority;
2839+
}
2840+
function shouldAttemptEagerTransition() {
2841+
return false;
28392842
} // The ART renderer is secondary to the React DOM renderer.
28402843

28412844
var warnsIfNotActing = false;
@@ -23095,6 +23098,7 @@ var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync i
2309523098

2309623099
var mightHavePendingSyncWork = false;
2309723100
var isFlushingWork = false;
23101+
var currentEventTransitionLane = NoLanes;
2309823102
function ensureRootIsScheduled(root) {
2309923103
// This function is called whenever a root receives an update. It does two
2310023104
// things 1) it ensures the root is in the root schedule, and 2) it ensures
@@ -23253,6 +23257,14 @@ function processRootScheduleInMicrotask() {
2325323257

2325423258
while (root !== null) {
2325523259
var next = root.next;
23260+
23261+
if (
23262+
currentEventTransitionLane !== NoLane &&
23263+
shouldAttemptEagerTransition()
23264+
) {
23265+
markRootEntangled(root, mergeLanes(currentEventTransitionLane, SyncLane));
23266+
}
23267+
2325623268
var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime);
2325723269

2325823270
if (nextLanes === NoLane) {
@@ -23284,7 +23296,9 @@ function processRootScheduleInMicrotask() {
2328423296
}
2328523297

2328623298
root = next;
23287-
} // At the end of the microtask, flush any pending synchronous work. This has
23299+
}
23300+
23301+
currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has
2328823302
// to come at the end, because it does actual rendering work that might throw.
2328923303

2329023304
flushSyncWorkOnAllRoots();
@@ -23457,6 +23471,13 @@ function scheduleImmediateTask(cb) {
2345723471
}
2345823472
}
2345923473

23474+
function getCurrentEventTransitionLane() {
23475+
return currentEventTransitionLane;
23476+
}
23477+
function setCurrentEventTransitionLane(lane) {
23478+
currentEventTransitionLane = lane;
23479+
}
23480+
2346023481
var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
2346123482
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher,
2346223483
ReactCurrentCache = ReactSharedInternals.ReactCurrentCache,
@@ -23722,7 +23743,6 @@ var didScheduleUpdateDuringPassiveEffects = false;
2372223743
var NESTED_PASSIVE_UPDATE_LIMIT = 50;
2372323744
var nestedPassiveUpdateCount = 0;
2372423745
var rootWithPassiveNestedUpdates = null;
23725-
var currentEventTransitionLane = NoLanes;
2372623746
var isRunningInsertionEffect = false;
2372723747
function getWorkInProgressRoot() {
2372823748
return workInProgressRoot;
@@ -23774,12 +23794,12 @@ function requestUpdateLane(fiber) {
2377423794
// event. Then reset the cached values once we can be sure the event is
2377523795
// over. Our heuristic for that is whenever we enter a concurrent work loop.
2377623796

23777-
if (currentEventTransitionLane === NoLane) {
23797+
if (getCurrentEventTransitionLane() === NoLane) {
2377823798
// All transitions within the same event are assigned the same lane.
23779-
currentEventTransitionLane = claimNextTransitionLane();
23799+
setCurrentEventTransitionLane(claimNextTransitionLane());
2378023800
}
2378123801

23782-
return currentEventTransitionLane;
23802+
return getCurrentEventTransitionLane();
2378323803
} // Updates originating inside certain React methods, like flushSync, have
2378423804
// their priority set by tracking it with a context variable.
2378523805
//
@@ -23956,8 +23976,6 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
2395623976
resetNestedUpdateFlag();
2395723977
}
2395823978

23959-
currentEventTransitionLane = NoLanes;
23960-
2396123979
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
2396223980
throw new Error("Should not already be working.");
2396323981
} // Flush any pending passive effects before deciding which lanes to work on,

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

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-modern-f2fcb129";
72+
var ReactVersion = "18.3.0-www-modern-c0c3e536";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -2833,6 +2833,9 @@ function shouldSetTextContent(type, props) {
28332833
}
28342834
function getCurrentEventPriority() {
28352835
return DefaultEventPriority;
2836+
}
2837+
function shouldAttemptEagerTransition() {
2838+
return false;
28362839
} // The ART renderer is secondary to the React DOM renderer.
28372840

28382841
var warnsIfNotActing = false;
@@ -22760,6 +22763,7 @@ var didScheduleMicrotask_act = false; // Used to quickly bail out of flushSync i
2276022763

2276122764
var mightHavePendingSyncWork = false;
2276222765
var isFlushingWork = false;
22766+
var currentEventTransitionLane = NoLanes;
2276322767
function ensureRootIsScheduled(root) {
2276422768
// This function is called whenever a root receives an update. It does two
2276522769
// things 1) it ensures the root is in the root schedule, and 2) it ensures
@@ -22918,6 +22922,14 @@ function processRootScheduleInMicrotask() {
2291822922

2291922923
while (root !== null) {
2292022924
var next = root.next;
22925+
22926+
if (
22927+
currentEventTransitionLane !== NoLane &&
22928+
shouldAttemptEagerTransition()
22929+
) {
22930+
markRootEntangled(root, mergeLanes(currentEventTransitionLane, SyncLane));
22931+
}
22932+
2292122933
var nextLanes = scheduleTaskForRootDuringMicrotask(root, currentTime);
2292222934

2292322935
if (nextLanes === NoLane) {
@@ -22949,7 +22961,9 @@ function processRootScheduleInMicrotask() {
2294922961
}
2295022962

2295122963
root = next;
22952-
} // At the end of the microtask, flush any pending synchronous work. This has
22964+
}
22965+
22966+
currentEventTransitionLane = NoLane; // At the end of the microtask, flush any pending synchronous work. This has
2295322967
// to come at the end, because it does actual rendering work that might throw.
2295422968

2295522969
flushSyncWorkOnAllRoots();
@@ -23122,6 +23136,13 @@ function scheduleImmediateTask(cb) {
2312223136
}
2312323137
}
2312423138

23139+
function getCurrentEventTransitionLane() {
23140+
return currentEventTransitionLane;
23141+
}
23142+
function setCurrentEventTransitionLane(lane) {
23143+
currentEventTransitionLane = lane;
23144+
}
23145+
2312523146
var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
2312623147
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher,
2312723148
ReactCurrentCache = ReactSharedInternals.ReactCurrentCache,
@@ -23387,7 +23408,6 @@ var didScheduleUpdateDuringPassiveEffects = false;
2338723408
var NESTED_PASSIVE_UPDATE_LIMIT = 50;
2338823409
var nestedPassiveUpdateCount = 0;
2338923410
var rootWithPassiveNestedUpdates = null;
23390-
var currentEventTransitionLane = NoLanes;
2339123411
var isRunningInsertionEffect = false;
2339223412
function getWorkInProgressRoot() {
2339323413
return workInProgressRoot;
@@ -23439,12 +23459,12 @@ function requestUpdateLane(fiber) {
2343923459
// event. Then reset the cached values once we can be sure the event is
2344023460
// over. Our heuristic for that is whenever we enter a concurrent work loop.
2344123461

23442-
if (currentEventTransitionLane === NoLane) {
23462+
if (getCurrentEventTransitionLane() === NoLane) {
2344323463
// All transitions within the same event are assigned the same lane.
23444-
currentEventTransitionLane = claimNextTransitionLane();
23464+
setCurrentEventTransitionLane(claimNextTransitionLane());
2344523465
}
2344623466

23447-
return currentEventTransitionLane;
23467+
return getCurrentEventTransitionLane();
2344823468
} // Updates originating inside certain React methods, like flushSync, have
2344923469
// their priority set by tracking it with a context variable.
2345023470
//
@@ -23621,8 +23641,6 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
2362123641
resetNestedUpdateFlag();
2362223642
}
2362323643

23624-
currentEventTransitionLane = NoLanes;
23625-
2362623644
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
2362723645
throw new Error("Should not already be working.");
2362823646
} // Flush any pending passive effects before deciding which lanes to work on,

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

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7655,7 +7655,8 @@ var DefaultCacheDispatcher = {
76557655
lastScheduledRoot = null,
76567656
didScheduleMicrotask = !1,
76577657
mightHavePendingSyncWork = !1,
7658-
isFlushingWork = !1;
7658+
isFlushingWork = !1,
7659+
currentEventTransitionLane = 0;
76597660
function ensureRootIsScheduled(root) {
76607661
root !== lastScheduledRoot &&
76617662
null === root.next &&
@@ -7774,6 +7775,7 @@ function processRootScheduleInMicrotask() {
77747775
0 !== (nextLanes & 3) && (mightHavePendingSyncWork = !0));
77757776
root = next;
77767777
}
7778+
currentEventTransitionLane = 0;
77777779
flushSyncWorkAcrossRoots_impl(!1);
77787780
}
77797781
function scheduleTaskForRootDuringMicrotask(root, currentTime) {
@@ -7942,8 +7944,7 @@ var hasUncaughtError = !1,
79427944
pendingPassiveEffectsRemainingLanes = 0,
79437945
pendingPassiveTransitions = null,
79447946
nestedUpdateCount = 0,
7945-
rootWithNestedUpdates = null,
7946-
currentEventTransitionLane = 0;
7947+
rootWithNestedUpdates = null;
79477948
function requestUpdateLane(fiber) {
79487949
if (0 === (fiber.mode & 1)) return 2;
79497950
if (0 !== (executionContext & 2) && 0 !== workInProgressRootRenderLanes)
@@ -7996,7 +7997,6 @@ function scheduleUpdateOnFiber(root, fiber, lane) {
79967997
}
79977998
}
79987999
function performConcurrentWorkOnRoot(root, didTimeout) {
7999-
currentEventTransitionLane = 0;
80008000
if (0 !== (executionContext & 6)) throw Error(formatProdErrorMessage(327));
80018001
var originalCallbackNode = root.callbackNode;
80028002
if (flushPassiveEffects() && root.callbackNode !== originalCallbackNode)
@@ -9967,19 +9967,19 @@ var slice = Array.prototype.slice,
99679967
};
99689968
return Text;
99699969
})(React.Component),
9970-
devToolsConfig$jscomp$inline_1170 = {
9970+
devToolsConfig$jscomp$inline_1172 = {
99719971
findFiberByHostInstance: function () {
99729972
return null;
99739973
},
99749974
bundleType: 0,
9975-
version: "18.3.0-www-classic-3d4daf47",
9975+
version: "18.3.0-www-classic-4755ac8c",
99769976
rendererPackageName: "react-art"
99779977
};
9978-
var internals$jscomp$inline_1335 = {
9979-
bundleType: devToolsConfig$jscomp$inline_1170.bundleType,
9980-
version: devToolsConfig$jscomp$inline_1170.version,
9981-
rendererPackageName: devToolsConfig$jscomp$inline_1170.rendererPackageName,
9982-
rendererConfig: devToolsConfig$jscomp$inline_1170.rendererConfig,
9978+
var internals$jscomp$inline_1337 = {
9979+
bundleType: devToolsConfig$jscomp$inline_1172.bundleType,
9980+
version: devToolsConfig$jscomp$inline_1172.version,
9981+
rendererPackageName: devToolsConfig$jscomp$inline_1172.rendererPackageName,
9982+
rendererConfig: devToolsConfig$jscomp$inline_1172.rendererConfig,
99839983
overrideHookState: null,
99849984
overrideHookStateDeletePath: null,
99859985
overrideHookStateRenamePath: null,
@@ -9996,26 +9996,26 @@ var internals$jscomp$inline_1335 = {
99969996
return null === fiber ? null : fiber.stateNode;
99979997
},
99989998
findFiberByHostInstance:
9999-
devToolsConfig$jscomp$inline_1170.findFiberByHostInstance ||
9999+
devToolsConfig$jscomp$inline_1172.findFiberByHostInstance ||
1000010000
emptyFindFiberByHostInstance,
1000110001
findHostInstancesForRefresh: null,
1000210002
scheduleRefresh: null,
1000310003
scheduleRoot: null,
1000410004
setRefreshHandler: null,
1000510005
getCurrentFiber: null,
10006-
reconcilerVersion: "18.3.0-www-classic-3d4daf47"
10006+
reconcilerVersion: "18.3.0-www-classic-4755ac8c"
1000710007
};
1000810008
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
10009-
var hook$jscomp$inline_1336 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
10009+
var hook$jscomp$inline_1338 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
1001010010
if (
10011-
!hook$jscomp$inline_1336.isDisabled &&
10012-
hook$jscomp$inline_1336.supportsFiber
10011+
!hook$jscomp$inline_1338.isDisabled &&
10012+
hook$jscomp$inline_1338.supportsFiber
1001310013
)
1001410014
try {
10015-
(rendererID = hook$jscomp$inline_1336.inject(
10016-
internals$jscomp$inline_1335
10015+
(rendererID = hook$jscomp$inline_1338.inject(
10016+
internals$jscomp$inline_1337
1001710017
)),
10018-
(injectedHook = hook$jscomp$inline_1336);
10018+
(injectedHook = hook$jscomp$inline_1338);
1001910019
} catch (err) {}
1002010020
}
1002110021
var Path = Mode$1.Path;

0 commit comments

Comments
 (0)