Skip to content

Commit 4fe69bf

Browse files
committed
[Fiber] Mark cascading updates (#31866)
A common source of performance problems is due to cascading renders from calling `setState` in `useLayoutEffect` or `useEffect`. This marks the entry from the update to when we start the render as red and `"Cascade"` to highlight this. <img width="964" alt="Screenshot 2024-12-19 at 10 54 59 PM" src="https://github.com/user-attachments/assets/2bfa91e6-1dc1-4b7f-a659-50aaf2a97e83" /> In addition to this case, there's another case where you call `setState` multiple times in the same event causing multiple renders. This might be due to multiple `flushSync`, or spawned a microtasks from a `useLayoutEffect`. In theory it could also be from a microtask scheduled after the first `setState`. This one we can only detect if it's from an event that has a `window.event` since otherwise it's hard to know if we're still in the same event. <img width="1210" alt="Screenshot 2024-12-19 at 11 38 44 PM" src="https://github.com/user-attachments/assets/ee188bc4-8ebb-4e95-b5a5-4d724856c27d" /> I decided against making a ping in a microtask considered a cascade. Because that should ideally be using the Suspense Optimization and so wouldn't be considered multi-pass. <img width="1284" alt="Screenshot 2024-12-19 at 11 07 30 PM" src="https://github.com/user-attachments/assets/2d173750-a475-41a0-b6cf-679d15c4ca97" /> We might consider making the whole render phase and maybe commit phase red but that should maybe reserved for actual errors. The "Blocked" phase really represents the `setState` and so will have the stack trace of the first update. DiffTrain build for [1e9eb95](1e9eb95)
1 parent e34e27e commit 4fe69bf

32 files changed

+304
-224
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1942,7 +1942,7 @@ __DEV__ &&
19421942
exports.useTransition = function () {
19431943
return resolveDispatcher().useTransition();
19441944
};
1945-
exports.version = "19.1.0-www-classic-fe21c947-20250102";
1945+
exports.version = "19.1.0-www-classic-1e9eb95d-20250102";
19461946
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19471947
"function" ===
19481948
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
@@ -1942,7 +1942,7 @@ __DEV__ &&
19421942
exports.useTransition = function () {
19431943
return resolveDispatcher().useTransition();
19441944
};
1945-
exports.version = "19.1.0-www-modern-fe21c947-20250102";
1945+
exports.version = "19.1.0-www-modern-1e9eb95d-20250102";
19461946
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19471947
"function" ===
19481948
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
@@ -630,4 +630,4 @@ exports.useSyncExternalStore = function (
630630
exports.useTransition = function () {
631631
return ReactSharedInternals.H.useTransition();
632632
};
633-
exports.version = "19.1.0-www-classic-fe21c947-20250102";
633+
exports.version = "19.1.0-www-classic-1e9eb95d-20250102";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,4 +630,4 @@ exports.useSyncExternalStore = function (
630630
exports.useTransition = function () {
631631
return ReactSharedInternals.H.useTransition();
632632
};
633-
exports.version = "19.1.0-www-modern-fe21c947-20250102";
633+
exports.version = "19.1.0-www-modern-1e9eb95d-20250102";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ exports.useSyncExternalStore = function (
634634
exports.useTransition = function () {
635635
return ReactSharedInternals.H.useTransition();
636636
};
637-
exports.version = "19.1.0-www-classic-fe21c947-20250102";
637+
exports.version = "19.1.0-www-classic-1e9eb95d-20250102";
638638
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
639639
"function" ===
640640
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
@@ -634,7 +634,7 @@ exports.useSyncExternalStore = function (
634634
exports.useTransition = function () {
635635
return ReactSharedInternals.H.useTransition();
636636
};
637-
exports.version = "19.1.0-www-modern-fe21c947-20250102";
637+
exports.version = "19.1.0-www-modern-1e9eb95d-20250102";
638638
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
639639
"function" ===
640640
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2289,11 +2289,9 @@ __DEV__ &&
22892289
mightHavePendingSyncWork = !0;
22902290
null !== ReactSharedInternals.actQueue
22912291
? didScheduleMicrotask_act ||
2292-
((didScheduleMicrotask_act = !0),
2293-
scheduleImmediateTask(processRootScheduleInMicrotask))
2292+
((didScheduleMicrotask_act = !0), scheduleImmediateRootScheduleTask())
22942293
: didScheduleMicrotask ||
2295-
((didScheduleMicrotask = !0),
2296-
scheduleImmediateTask(processRootScheduleInMicrotask));
2294+
((didScheduleMicrotask = !0), scheduleImmediateRootScheduleTask());
22972295
enableDeferRootSchedulingToMicrotask ||
22982296
scheduleTaskForRootDuringMicrotask(root, now$1());
22992297
}
@@ -2339,6 +2337,9 @@ __DEV__ &&
23392337
isFlushingWork = !1;
23402338
}
23412339
}
2340+
function processRootScheduleInImmediateTask() {
2341+
processRootScheduleInMicrotask();
2342+
}
23422343
function processRootScheduleInMicrotask() {
23432344
mightHavePendingSyncWork =
23442345
didScheduleMicrotask_act =
@@ -2477,13 +2478,13 @@ __DEV__ &&
24772478
null !== callbackNode &&
24782479
cancelCallback$1(callbackNode);
24792480
}
2480-
function scheduleImmediateTask(cb) {
2481+
function scheduleImmediateRootScheduleTask() {
24812482
null !== ReactSharedInternals.actQueue &&
24822483
ReactSharedInternals.actQueue.push(function () {
2483-
cb();
2484+
processRootScheduleInMicrotask();
24842485
return null;
24852486
});
2486-
scheduleCallback$3(ImmediatePriority, cb);
2487+
scheduleCallback$3(ImmediatePriority, processRootScheduleInImmediateTask);
24872488
}
24882489
function requestTransitionLane() {
24892490
0 === currentEventTransitionLane &&
@@ -16894,10 +16895,10 @@ __DEV__ &&
1689416895
(function () {
1689516896
var internals = {
1689616897
bundleType: 1,
16897-
version: "19.1.0-www-classic-fe21c947-20250102",
16898+
version: "19.1.0-www-classic-1e9eb95d-20250102",
1689816899
rendererPackageName: "react-art",
1689916900
currentDispatcherRef: ReactSharedInternals,
16900-
reconcilerVersion: "19.1.0-www-classic-fe21c947-20250102"
16901+
reconcilerVersion: "19.1.0-www-classic-1e9eb95d-20250102"
1690116902
};
1690216903
internals.overrideHookState = overrideHookState;
1690316904
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16931,7 +16932,7 @@ __DEV__ &&
1693116932
exports.Shape = Shape;
1693216933
exports.Surface = Surface;
1693316934
exports.Text = Text;
16934-
exports.version = "19.1.0-www-classic-fe21c947-20250102";
16935+
exports.version = "19.1.0-www-classic-1e9eb95d-20250102";
1693516936
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1693616937
"function" ===
1693716938
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,11 +2181,9 @@ __DEV__ &&
21812181
mightHavePendingSyncWork = !0;
21822182
null !== ReactSharedInternals.actQueue
21832183
? didScheduleMicrotask_act ||
2184-
((didScheduleMicrotask_act = !0),
2185-
scheduleImmediateTask(processRootScheduleInMicrotask))
2184+
((didScheduleMicrotask_act = !0), scheduleImmediateRootScheduleTask())
21862185
: didScheduleMicrotask ||
2187-
((didScheduleMicrotask = !0),
2188-
scheduleImmediateTask(processRootScheduleInMicrotask));
2186+
((didScheduleMicrotask = !0), scheduleImmediateRootScheduleTask());
21892187
enableDeferRootSchedulingToMicrotask ||
21902188
scheduleTaskForRootDuringMicrotask(root, now$1());
21912189
}
@@ -2231,6 +2229,9 @@ __DEV__ &&
22312229
isFlushingWork = !1;
22322230
}
22332231
}
2232+
function processRootScheduleInImmediateTask() {
2233+
processRootScheduleInMicrotask();
2234+
}
22342235
function processRootScheduleInMicrotask() {
22352236
mightHavePendingSyncWork =
22362237
didScheduleMicrotask_act =
@@ -2369,13 +2370,13 @@ __DEV__ &&
23692370
null !== callbackNode &&
23702371
cancelCallback$1(callbackNode);
23712372
}
2372-
function scheduleImmediateTask(cb) {
2373+
function scheduleImmediateRootScheduleTask() {
23732374
null !== ReactSharedInternals.actQueue &&
23742375
ReactSharedInternals.actQueue.push(function () {
2375-
cb();
2376+
processRootScheduleInMicrotask();
23762377
return null;
23772378
});
2378-
scheduleCallback$3(ImmediatePriority, cb);
2379+
scheduleCallback$3(ImmediatePriority, processRootScheduleInImmediateTask);
23792380
}
23802381
function requestTransitionLane() {
23812382
0 === currentEventTransitionLane &&
@@ -16657,10 +16658,10 @@ __DEV__ &&
1665716658
(function () {
1665816659
var internals = {
1665916660
bundleType: 1,
16660-
version: "19.1.0-www-modern-fe21c947-20250102",
16661+
version: "19.1.0-www-modern-1e9eb95d-20250102",
1666116662
rendererPackageName: "react-art",
1666216663
currentDispatcherRef: ReactSharedInternals,
16663-
reconcilerVersion: "19.1.0-www-modern-fe21c947-20250102"
16664+
reconcilerVersion: "19.1.0-www-modern-1e9eb95d-20250102"
1666416665
};
1666516666
internals.overrideHookState = overrideHookState;
1666616667
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16694,7 +16695,7 @@ __DEV__ &&
1669416695
exports.Shape = Shape;
1669516696
exports.Surface = Surface;
1669616697
exports.Text = Text;
16697-
exports.version = "19.1.0-www-modern-fe21c947-20250102";
16698+
exports.version = "19.1.0-www-modern-1e9eb95d-20250102";
1669816699
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1669916700
"function" ===
1670016701
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,7 @@ function ensureRootIsScheduled(root) {
13481348
mightHavePendingSyncWork = !0;
13491349
didScheduleMicrotask ||
13501350
((didScheduleMicrotask = !0),
1351-
scheduleCallback$3(ImmediatePriority, processRootScheduleInMicrotask));
1351+
scheduleCallback$3(ImmediatePriority, processRootScheduleInImmediateTask));
13521352
enableDeferRootSchedulingToMicrotask ||
13531353
scheduleTaskForRootDuringMicrotask(root, now());
13541354
}
@@ -1395,7 +1395,7 @@ function flushSyncWorkAcrossRoots_impl(syncTransitionLanes, onlyLegacy) {
13951395
isFlushingWork = !1;
13961396
}
13971397
}
1398-
function processRootScheduleInMicrotask() {
1398+
function processRootScheduleInImmediateTask() {
13991399
mightHavePendingSyncWork = didScheduleMicrotask = !1;
14001400
0 !== currentEventTransitionLane && (currentEventTransitionLane = 0);
14011401
for (
@@ -10777,24 +10777,24 @@ var slice = Array.prototype.slice,
1077710777
};
1077810778
return Text;
1077910779
})(React.Component);
10780-
var internals$jscomp$inline_1501 = {
10780+
var internals$jscomp$inline_1507 = {
1078110781
bundleType: 0,
10782-
version: "19.1.0-www-classic-fe21c947-20250102",
10782+
version: "19.1.0-www-classic-1e9eb95d-20250102",
1078310783
rendererPackageName: "react-art",
1078410784
currentDispatcherRef: ReactSharedInternals,
10785-
reconcilerVersion: "19.1.0-www-classic-fe21c947-20250102"
10785+
reconcilerVersion: "19.1.0-www-classic-1e9eb95d-20250102"
1078610786
};
1078710787
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
10788-
var hook$jscomp$inline_1502 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
10788+
var hook$jscomp$inline_1508 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
1078910789
if (
10790-
!hook$jscomp$inline_1502.isDisabled &&
10791-
hook$jscomp$inline_1502.supportsFiber
10790+
!hook$jscomp$inline_1508.isDisabled &&
10791+
hook$jscomp$inline_1508.supportsFiber
1079210792
)
1079310793
try {
10794-
(rendererID = hook$jscomp$inline_1502.inject(
10795-
internals$jscomp$inline_1501
10794+
(rendererID = hook$jscomp$inline_1508.inject(
10795+
internals$jscomp$inline_1507
1079610796
)),
10797-
(injectedHook = hook$jscomp$inline_1502);
10797+
(injectedHook = hook$jscomp$inline_1508);
1079810798
} catch (err) {}
1079910799
}
1080010800
var Path = Mode$1.Path;
@@ -10808,4 +10808,4 @@ exports.RadialGradient = RadialGradient;
1080810808
exports.Shape = TYPES.SHAPE;
1080910809
exports.Surface = Surface;
1081010810
exports.Text = Text;
10811-
exports.version = "19.1.0-www-classic-fe21c947-20250102";
10811+
exports.version = "19.1.0-www-classic-1e9eb95d-20250102";

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,7 @@ function ensureRootIsScheduled(root) {
11951195
mightHavePendingSyncWork = !0;
11961196
didScheduleMicrotask ||
11971197
((didScheduleMicrotask = !0),
1198-
scheduleCallback$3(ImmediatePriority, processRootScheduleInMicrotask));
1198+
scheduleCallback$3(ImmediatePriority, processRootScheduleInImmediateTask));
11991199
enableDeferRootSchedulingToMicrotask ||
12001200
scheduleTaskForRootDuringMicrotask(root, now());
12011201
}
@@ -1242,7 +1242,7 @@ function flushSyncWorkAcrossRoots_impl(syncTransitionLanes, onlyLegacy) {
12421242
isFlushingWork = !1;
12431243
}
12441244
}
1245-
function processRootScheduleInMicrotask() {
1245+
function processRootScheduleInImmediateTask() {
12461246
mightHavePendingSyncWork = didScheduleMicrotask = !1;
12471247
0 !== currentEventTransitionLane && (currentEventTransitionLane = 0);
12481248
for (
@@ -10493,24 +10493,24 @@ var slice = Array.prototype.slice,
1049310493
};
1049410494
return Text;
1049510495
})(React.Component);
10496-
var internals$jscomp$inline_1480 = {
10496+
var internals$jscomp$inline_1486 = {
1049710497
bundleType: 0,
10498-
version: "19.1.0-www-modern-fe21c947-20250102",
10498+
version: "19.1.0-www-modern-1e9eb95d-20250102",
1049910499
rendererPackageName: "react-art",
1050010500
currentDispatcherRef: ReactSharedInternals,
10501-
reconcilerVersion: "19.1.0-www-modern-fe21c947-20250102"
10501+
reconcilerVersion: "19.1.0-www-modern-1e9eb95d-20250102"
1050210502
};
1050310503
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
10504-
var hook$jscomp$inline_1481 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
10504+
var hook$jscomp$inline_1487 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
1050510505
if (
10506-
!hook$jscomp$inline_1481.isDisabled &&
10507-
hook$jscomp$inline_1481.supportsFiber
10506+
!hook$jscomp$inline_1487.isDisabled &&
10507+
hook$jscomp$inline_1487.supportsFiber
1050810508
)
1050910509
try {
10510-
(rendererID = hook$jscomp$inline_1481.inject(
10511-
internals$jscomp$inline_1480
10510+
(rendererID = hook$jscomp$inline_1487.inject(
10511+
internals$jscomp$inline_1486
1051210512
)),
10513-
(injectedHook = hook$jscomp$inline_1481);
10513+
(injectedHook = hook$jscomp$inline_1487);
1051410514
} catch (err) {}
1051510515
}
1051610516
var Path = Mode$1.Path;
@@ -10524,4 +10524,4 @@ exports.RadialGradient = RadialGradient;
1052410524
exports.Shape = TYPES.SHAPE;
1052510525
exports.Surface = Surface;
1052610526
exports.Text = Text;
10527-
exports.version = "19.1.0-www-modern-fe21c947-20250102";
10527+
exports.version = "19.1.0-www-modern-1e9eb95d-20250102";

0 commit comments

Comments
 (0)