Skip to content

Commit 3c958c0

Browse files
committed
[Fiber] Trigger default transition indicator if needed (#33160)
Stacked on #33159. This implements `onDefaultTransitionIndicator`. The sequence is: 1) In `markRootUpdated` we schedule Transition updates as needing `indicatorLanes` on the root. This tracks the lanes that currently need an indicator to either start or remain going until this lane commits. 2) Track mutations during any commit. We use the same hook that view transitions use here but instead of tracking it just per view transition scope, we also track a global boolean for the whole root. 3) If a sync/default commit had any mutations, then we clear the indicator lane for the `currentEventTransitionLane`. This requires that the lane is still active while we do these commits. See #33159. In other words, a sync update gets associated with the current transition and it is assumed to be rendering the loading state for that corresponding transition so we don't need a default indicator for this lane. 4) At the end of `processRootScheduleInMicrotask`, right before we're about to enter a new "event transition lane" scope, it is no longer possible to render any more loading states for the current transition lane. That's when we invoke `onDefaultTransitionIndicator` for any roots that have new indicator lanes. 5) When we commit, we remove the finished lanes from `indicatorLanes` and once that reaches zero again, then we can clean up the default indicator. This approach means that you can start multiple different transitions while an indicator is still going but it won't stop/restart each time. Instead, it'll wait until all are done before stopping. Follow ups: - [x] Default updates are currently not enough to cancel because those aren't flush in the same microtask. That's unfortunate. #33186 - [x] Handle async actions before the setState. Since these don't necessarily have a root this is tricky. #33190 - [x] Disable for `useDeferredValue`. ~Since it also goes through `markRootUpdated` and schedules a Transition lane it'll get a default indicator even though it probably shouldn't have one.~ EDIT: Turns out this just works because it doesn't go through `markRootUpdated` when work is left behind. - [x] Implement built-in DOM version by default. #33162 DiffTrain build for [62d3f36](62d3f36)
1 parent d23c7aa commit 3c958c0

34 files changed

+1510
-1446
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
676f0879f315130309262ff3532707029f0288bb
1+
62d3f36ea79fc0a10b514d4bbcc4ba3f21b3206e
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
676f0879f315130309262ff3532707029f0288bb
1+
62d3f36ea79fc0a10b514d4bbcc4ba3f21b3206e

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1537,7 +1537,7 @@ __DEV__ &&
15371537
exports.useTransition = function () {
15381538
return resolveDispatcher().useTransition();
15391539
};
1540-
exports.version = "19.2.0-www-classic-676f0879-20250513";
1540+
exports.version = "19.2.0-www-classic-62d3f36e-20250513";
15411541
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15421542
"function" ===
15431543
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
@@ -1537,7 +1537,7 @@ __DEV__ &&
15371537
exports.useTransition = function () {
15381538
return resolveDispatcher().useTransition();
15391539
};
1540-
exports.version = "19.2.0-www-modern-676f0879-20250513";
1540+
exports.version = "19.2.0-www-modern-62d3f36e-20250513";
15411541
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15421542
"function" ===
15431543
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
@@ -635,4 +635,4 @@ exports.useSyncExternalStore = function (
635635
exports.useTransition = function () {
636636
return ReactSharedInternals.H.useTransition();
637637
};
638-
exports.version = "19.2.0-www-classic-676f0879-20250513";
638+
exports.version = "19.2.0-www-classic-62d3f36e-20250513";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,4 +635,4 @@ exports.useSyncExternalStore = function (
635635
exports.useTransition = function () {
636636
return ReactSharedInternals.H.useTransition();
637637
};
638-
exports.version = "19.2.0-www-modern-676f0879-20250513";
638+
exports.version = "19.2.0-www-modern-62d3f36e-20250513";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ exports.useSyncExternalStore = function (
639639
exports.useTransition = function () {
640640
return ReactSharedInternals.H.useTransition();
641641
};
642-
exports.version = "19.2.0-www-classic-676f0879-20250513";
642+
exports.version = "19.2.0-www-classic-62d3f36e-20250513";
643643
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
644644
"function" ===
645645
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
@@ -639,7 +639,7 @@ exports.useSyncExternalStore = function (
639639
exports.useTransition = function () {
640640
return ReactSharedInternals.H.useTransition();
641641
};
642-
exports.version = "19.2.0-www-modern-676f0879-20250513";
642+
exports.version = "19.2.0-www-modern-62d3f36e-20250513";
643643
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
644644
"function" ===
645645
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2753,6 +2753,7 @@ __DEV__ &&
27532753
for (var child = fiber.child; child; )
27542754
(fiber.actualDuration += child.actualDuration), (child = child.sibling);
27552755
}
2756+
function noop() {}
27562757
function ensureRootIsScheduled(root) {
27572758
root !== lastScheduledRoot &&
27582759
null === root.next &&
@@ -2836,7 +2837,7 @@ __DEV__ &&
28362837
(pendingEffectsStatus !== NO_PENDING_EFFECTS &&
28372838
pendingEffectsStatus !== PENDING_PASSIVE_PHASE) ||
28382839
flushSyncWorkAcrossRoots_impl(0, !1);
2839-
currentEventTransitionLane = 0;
2840+
0 !== currentEventTransitionLane && (currentEventTransitionLane = 0);
28402841
}
28412842
function scheduleTaskForRootDuringMicrotask(root, currentTime) {
28422843
var pendingLanes = root.pendingLanes,
@@ -2971,8 +2972,11 @@ __DEV__ &&
29712972
scheduleCallback$3(ImmediatePriority, processRootScheduleInImmediateTask);
29722973
}
29732974
function requestTransitionLane() {
2974-
0 === currentEventTransitionLane &&
2975-
(currentEventTransitionLane = claimNextTransitionLane());
2975+
if (0 === currentEventTransitionLane) {
2976+
var actionScopeLane = currentEntangledLane;
2977+
currentEventTransitionLane =
2978+
0 !== actionScopeLane ? actionScopeLane : claimNextTransitionLane();
2979+
}
29762980
return currentEventTransitionLane;
29772981
}
29782982
function entangleAsyncAction(transition, thenable) {
@@ -3096,7 +3100,6 @@ __DEV__ &&
30963100
}
30973101
return !0;
30983102
}
3099-
function noop() {}
31003103
function createThenableState() {
31013104
return { didWarnAboutUncachedPromise: !1, thenables: [] };
31023105
}
@@ -12121,9 +12124,11 @@ __DEV__ &&
1212112124
break;
1212212125
case 3:
1212312126
flags = pushNestedEffectDurations();
12127+
enableViewTransition && (viewTransitionMutationContext = !1);
1212412128
recursivelyTraverseMutationEffects(root, finishedWork, lanes);
1212512129
commitReconciliationEffects(finishedWork);
1212612130
root.effectDuration += popNestedEffectDurations(flags);
12131+
enableViewTransition && (viewTransitionMutationContext = !1);
1212712132
break;
1212812133
case 4:
1212912134
flags = pushMutationContext();
@@ -13911,8 +13916,7 @@ __DEV__ &&
1391113916
return null !== transition
1391213917
? (transition._updatedFibers || (transition._updatedFibers = new Set()),
1391313918
transition._updatedFibers.add(fiber),
13914-
(fiber = currentEntangledLane),
13915-
0 !== fiber ? fiber : requestTransitionLane())
13919+
requestTransitionLane())
1391613920
: currentUpdatePriority || DefaultEventPriority;
1391713921
}
1391813922
function requestDeferredLane() {
@@ -15535,9 +15539,9 @@ __DEV__ &&
1553515539
if (0 !== (finishedWork.subtreeFlags & 8772) || rootHasLayoutEffect) {
1553615540
rootHasLayoutEffect = ReactSharedInternals.T;
1553715541
ReactSharedInternals.T = null;
15538-
var previousPriority = currentUpdatePriority;
15542+
var _previousPriority = currentUpdatePriority;
1553915543
currentUpdatePriority = DiscreteEventPriority;
15540-
var prevExecutionContext = executionContext;
15544+
var _prevExecutionContext = executionContext;
1554115545
executionContext |= CommitContext;
1554215546
try {
1554315547
enableSchedulingProfiler &&
@@ -15562,8 +15566,8 @@ __DEV__ &&
1556215566
typeof injectedProfilingHooks.markLayoutEffectsStopped &&
1556315567
injectedProfilingHooks.markLayoutEffectsStopped();
1556415568
} finally {
15565-
(executionContext = prevExecutionContext),
15566-
(currentUpdatePriority = previousPriority),
15569+
(executionContext = _prevExecutionContext),
15570+
(currentUpdatePriority = _previousPriority),
1556715571
(ReactSharedInternals.T = rootHasLayoutEffect);
1556815572
}
1556915573
}
@@ -17014,6 +17018,35 @@ __DEV__ &&
1701417018
};
1701517019
}
1701617020
var objectIs = "function" === typeof Object.is ? Object.is : is,
17021+
reportGlobalError =
17022+
"function" === typeof reportError
17023+
? reportError
17024+
: function (error) {
17025+
if (
17026+
"object" === typeof window &&
17027+
"function" === typeof window.ErrorEvent
17028+
) {
17029+
var event = new window.ErrorEvent("error", {
17030+
bubbles: !0,
17031+
cancelable: !0,
17032+
message:
17033+
"object" === typeof error &&
17034+
null !== error &&
17035+
"string" === typeof error.message
17036+
? String(error.message)
17037+
: String(error),
17038+
error: error
17039+
});
17040+
if (!window.dispatchEvent(event)) return;
17041+
} else if (
17042+
"object" === typeof process &&
17043+
"function" === typeof process.emit
17044+
) {
17045+
process.emit("uncaughtException", error);
17046+
return;
17047+
}
17048+
console.error(error);
17049+
},
1701717050
supportsUserTiming =
1701817051
"undefined" !== typeof console &&
1701917052
"function" === typeof console.timeStamp,
@@ -18665,35 +18698,6 @@ __DEV__ &&
1866518698
injectedProfilingHooks.markForceUpdateScheduled(inst, lane);
1866618699
}
1866718700
},
18668-
reportGlobalError =
18669-
"function" === typeof reportError
18670-
? reportError
18671-
: function (error) {
18672-
if (
18673-
"object" === typeof window &&
18674-
"function" === typeof window.ErrorEvent
18675-
) {
18676-
var event = new window.ErrorEvent("error", {
18677-
bubbles: !0,
18678-
cancelable: !0,
18679-
message:
18680-
"object" === typeof error &&
18681-
null !== error &&
18682-
"string" === typeof error.message
18683-
? String(error.message)
18684-
: String(error),
18685-
error: error
18686-
});
18687-
if (!window.dispatchEvent(event)) return;
18688-
} else if (
18689-
"object" === typeof process &&
18690-
"function" === typeof process.emit
18691-
) {
18692-
process.emit("uncaughtException", error);
18693-
return;
18694-
}
18695-
console.error(error);
18696-
},
1869718701
componentName = null,
1869818702
errorBoundaryName = null,
1869918703
TransitionRoot = 0,
@@ -19065,10 +19069,10 @@ __DEV__ &&
1906519069
(function () {
1906619070
var internals = {
1906719071
bundleType: 1,
19068-
version: "19.2.0-www-classic-676f0879-20250513",
19072+
version: "19.2.0-www-classic-62d3f36e-20250513",
1906919073
rendererPackageName: "react-art",
1907019074
currentDispatcherRef: ReactSharedInternals,
19071-
reconcilerVersion: "19.2.0-www-classic-676f0879-20250513"
19075+
reconcilerVersion: "19.2.0-www-classic-62d3f36e-20250513"
1907219076
};
1907319077
internals.overrideHookState = overrideHookState;
1907419078
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -19102,7 +19106,7 @@ __DEV__ &&
1910219106
exports.Shape = Shape;
1910319107
exports.Surface = Surface;
1910419108
exports.Text = Text;
19105-
exports.version = "19.2.0-www-classic-676f0879-20250513";
19109+
exports.version = "19.2.0-www-classic-62d3f36e-20250513";
1910619110
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1910719111
"function" ===
1910819112
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)