[Tracks] Annotate devtools.performanceIssue for Cascading Updates in DEV (#34961)
Alex Hunt committed
Nov 4, 2025 at 17:07 UTC
d000261eef6109c332a1880e92836856473f6a39
8 files changed
+28
packages/react-reconciler/src/ReactFiberPerformanceTrack.js
+15
@@ -36,6 +36,7 @@ import {
36
import {
37
enableProfilerTimer,
38
enableGestureTransition,
39
+ enablePerformanceIssueReporting,
40
} from 'shared/ReactFeatureFlags';
41
42
const supportsUserTiming =
@@ -203,6 +204,15 @@ const reusableComponentOptions: PerformanceMeasureOptions = {
204
205
const reusableChangedPropsEntry = ['Changed Props', ''];
206
207
+const reusableCascadingUpdateIssue = {
208
+ name: 'React: Cascading Update',
209
+ severity: 'warning',
210
+ description:
211
+ 'A cascading update is an update that is triggered during an ongoing render. This can lead to performance issues.',
212
+ learnMoreUrl:
213
+ 'https://react.dev/reference/dev-tools/react-performance-tracks#cascading-updates',
214
+};
215
+
216
const DEEP_EQUALITY_WARNING =
217
'This component received deeply equal props. It might benefit from useMemo or the React Compiler in its owner.';
218
@@ -761,6 +771,11 @@ export function logBlockingStart(
771
},
772
},
773
};
774
+ if (enablePerformanceIssueReporting && isSpawnedUpdate) {
775
+ // $FlowFixMe[prop-missing] - detail is untyped
776
+ measureOptions.detail.devtools.performanceIssue =
777
+ reusableCascadingUpdateIssue;
778
+ }
779
780
if (debugTask) {
781
debugTask.run(
packages/shared/ReactFeatureFlags.js
+5
@@ -232,6 +232,11 @@ export const enableProfilerTimer = __PROFILE__;
232
// All calls should also be gated on enableProfilerTimer.
233
export const enableComponentPerformanceTrack: boolean = true;
234
235
+// Enables annotating of React performance track events with `performanceIssue`
236
+// metadata, to more prominently highlight performance issues to users
237
+// (initially, an experimental feature in React Native).
238
+export const enablePerformanceIssueReporting: boolean = false;
239
+
240
// Adds user timing marks for e.g. state updates, suspense, and work loop stuff,
241
// for an experimental timeline tool.
242
export const enableSchedulingProfiler: boolean =
packages/shared/forks/ReactFeatureFlags.native-fb.js
+2
@@ -83,6 +83,8 @@ export const enableDefaultTransitionIndicator: boolean = true;
83
export const ownerStackLimit = 1e4;
84
export const enableComponentPerformanceTrack: boolean =
85
__PROFILE__ && dynamicFlags.enableComponentPerformanceTrack;
86
+export const enablePerformanceIssueReporting: boolean =
87
+ enableComponentPerformanceTrack;
88
89
// Flow magic to verify the exports of this file match the original version.
90
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -42,6 +42,7 @@ export const enablePostpone: boolean = false;
42
export const enableReactTestRendererWarning: boolean = false;
43
export const enableRetryLaneExpiration: boolean = false;
44
export const enableComponentPerformanceTrack: boolean = true;
45
+export const enablePerformanceIssueReporting: boolean = false;
46
export const enableSchedulingProfiler: boolean =
47
!enableComponentPerformanceTrack && __PROFILE__;
48
export const enableScopeAPI: boolean = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -16,6 +16,7 @@ export const enableProfilerTimer: boolean = __PROFILE__;
16
export const enableProfilerCommitHooks: boolean = __PROFILE__;
17
export const enableProfilerNestedUpdatePhase: boolean = __PROFILE__;
18
export const enableComponentPerformanceTrack: boolean = true;
19
+export const enablePerformanceIssueReporting: boolean = false;
20
export const enableUpdaterTracking: boolean = false;
21
export const enableLegacyCache: boolean = __EXPERIMENTAL__;
22
export const enableAsyncIterableChildren: boolean = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
+1
@@ -41,6 +41,7 @@ export const enableReactTestRendererWarning = false;
41
export const enableRetryLaneExpiration = false;
42
export const enableSchedulingProfiler = __PROFILE__;
43
export const enableComponentPerformanceTrack = false;
44
+export const enablePerformanceIssueReporting = false;
45
export const enableScopeAPI = false;
46
export const enableEagerAlternateStateNodeCleanup = true;
47
export const enableSuspenseAvoidThisFallback = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -16,6 +16,7 @@ export const enableProfilerTimer: boolean = __PROFILE__;
16
export const enableProfilerCommitHooks: boolean = __PROFILE__;
17
export const enableProfilerNestedUpdatePhase: boolean = __PROFILE__;
18
export const enableComponentPerformanceTrack: boolean = false;
19
+export const enablePerformanceIssueReporting: boolean = false;
20
export const enableUpdaterTracking: boolean = false;
21
export const enableLegacyCache: boolean = true;
22
export const enableAsyncIterableChildren: boolean = false;
packages/shared/forks/ReactFeatureFlags.www.js
+2
@@ -59,6 +59,8 @@ export const enableThrottledScheduling: boolean = false;
59
60
export const enableHydrationLaneScheduling: boolean = true;
61
62
+export const enablePerformanceIssueReporting: boolean = false;
63
+
64
// Logs additional User Timing API marks for use with an experimental profiling tool.
65
export const enableSchedulingProfiler: boolean =
66
__PROFILE__ && dynamicFeatureFlags.enableSchedulingProfiler;