Skip to content

Commit 7c4f85d

Browse files
author
Brian Vaughn
committed
Add Profiler callback when nested udpates are scheduled
This callback accepts the no parameters (except for the current interactions). Users of this hook can inspect the call stack to access and log the source location of the component.
1 parent 393c452 commit 7c4f85d

13 files changed

+617
-0
lines changed

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
replayFailedUnitOfWorkWithInvokeGuardedCallback,
2323
enableProfilerTimer,
2424
enableProfilerNestedUpdatePhase,
25+
enableProfilerNestedUpdateScheduledHook,
2526
enableSchedulerTracing,
2627
warnAboutUnmockedScheduler,
2728
deferRenderPhaseUpdateToNextBatch,
@@ -110,6 +111,7 @@ import {
110111
ForwardRef,
111112
MemoComponent,
112113
SimpleMemoComponent,
114+
Profiler,
113115
} from './ReactWorkTags';
114116
import {LegacyRoot} from './ReactRootTags';
115117
import {
@@ -258,6 +260,10 @@ let workInProgress: Fiber | null = null;
258260
// The lanes we're rendering
259261
let workInProgressRootRenderLanes: Lanes = NoLanes;
260262

263+
// Only used when enableProfilerNestedUpdateScheduledHook is true;
264+
// to track which root is currently committing layout effects.
265+
let rootCommittingMutationOrLayoutEffects: FiberRoot | null = null;
266+
261267
// Stack that allows components to change the render lanes for its subtree
262268
// This is a superset of the lanes we started working on at the root. The only
263269
// case where it's different from `workInProgressRootRenderLanes` is when we
@@ -509,6 +515,30 @@ export function scheduleUpdateOnFiber(
509515
// Mark that the root has a pending update.
510516
markRootUpdated(root, lane, eventTime);
511517

518+
if (enableProfilerNestedUpdateScheduledHook) {
519+
if (
520+
executionContext === CommitContext &&
521+
root === rootCommittingMutationOrLayoutEffects
522+
) {
523+
if (fiber.mode & ProfileMode) {
524+
let current = fiber;
525+
while (current !== null) {
526+
if (current.tag === Profiler) {
527+
const {onNestedUpdateScheduled} = current.memoizedProps;
528+
if (typeof onNestedUpdateScheduled === 'function') {
529+
if (enableSchedulerTracing) {
530+
onNestedUpdateScheduled(root.memoizedInteractions);
531+
} else {
532+
onNestedUpdateScheduled();
533+
}
534+
}
535+
}
536+
current = current.return;
537+
}
538+
}
539+
}
540+
}
541+
512542
if (root === workInProgressRoot) {
513543
// Received an update to a tree that's in the middle of rendering. Mark
514544
// that there was an interleaved update work on this root. Unless the
@@ -1898,6 +1928,10 @@ function commitRootImpl(root, renderPriorityLevel) {
18981928
recordCommitTime();
18991929
}
19001930

1931+
if (enableProfilerNestedUpdateScheduledHook) {
1932+
rootCommittingMutationOrLayoutEffects = root;
1933+
}
1934+
19011935
// The next phase is the mutation phase, where we mutate the host tree.
19021936
commitMutationEffects(finishedWork, root, renderPriorityLevel);
19031937

@@ -1936,6 +1970,10 @@ function commitRootImpl(root, renderPriorityLevel) {
19361970
markLayoutEffectsStopped();
19371971
}
19381972

1973+
if (enableProfilerNestedUpdateScheduledHook) {
1974+
rootCommittingMutationOrLayoutEffects = null;
1975+
}
1976+
19391977
// Tell Scheduler to yield at the end of the frame, so the browser has an
19401978
// opportunity to paint.
19411979
requestPaint();

packages/react-reconciler/src/ReactFiberWorkLoop.old.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
enableProfilerTimer,
2424
enableProfilerCommitHooks,
2525
enableProfilerNestedUpdatePhase,
26+
enableProfilerNestedUpdateScheduledHook,
2627
enableSchedulerTracing,
2728
warnAboutUnmockedScheduler,
2829
deferRenderPhaseUpdateToNextBatch,
@@ -112,6 +113,7 @@ import {
112113
OffscreenComponent,
113114
LegacyHiddenComponent,
114115
ScopeComponent,
116+
Profiler,
115117
} from './ReactWorkTags';
116118
import {LegacyRoot} from './ReactRootTags';
117119
import {
@@ -329,6 +331,10 @@ let hasUncaughtError = false;
329331
let firstUncaughtError = null;
330332
let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;
331333

334+
// Only used when enableProfilerNestedUpdateScheduledHook is true;
335+
// to track which root is currently committing layout effects.
336+
let rootCommittingMutationOrLayoutEffects: FiberRoot | null = null;
337+
332338
let rootDoesHavePassiveEffects: boolean = false;
333339
let rootWithPendingPassiveEffects: FiberRoot | null = null;
334340
let pendingPassiveEffectsRenderPriority: ReactPriorityLevel = NoSchedulerPriority;
@@ -533,6 +539,30 @@ export function scheduleUpdateOnFiber(
533539
// Mark that the root has a pending update.
534540
markRootUpdated(root, lane, eventTime);
535541

542+
if (enableProfilerNestedUpdateScheduledHook) {
543+
if (
544+
executionContext === CommitContext &&
545+
root === rootCommittingMutationOrLayoutEffects
546+
) {
547+
if (fiber.mode & ProfileMode) {
548+
let current = fiber;
549+
while (current !== null) {
550+
if (current.tag === Profiler) {
551+
const {onNestedUpdateScheduled} = current.memoizedProps;
552+
if (typeof onNestedUpdateScheduled === 'function') {
553+
if (enableSchedulerTracing) {
554+
onNestedUpdateScheduled(root.memoizedInteractions);
555+
} else {
556+
onNestedUpdateScheduled();
557+
}
558+
}
559+
}
560+
current = current.return;
561+
}
562+
}
563+
}
564+
}
565+
536566
if (root === workInProgressRoot) {
537567
// Received an update to a tree that's in the middle of rendering. Mark
538568
// that there was an interleaved update work on this root. Unless the
@@ -2047,6 +2077,12 @@ function commitRootImpl(root, renderPriorityLevel) {
20472077
recordCommitTime();
20482078
}
20492079

2080+
if (enableProfilerNestedUpdateScheduledHook) {
2081+
// Track the root here, rather than in commitLayoutEffects(), because of ref setters.
2082+
// Updates scheduled during ref detachment should also be flagged.
2083+
rootCommittingMutationOrLayoutEffects = root;
2084+
}
2085+
20502086
// The next phase is the mutation phase, where we mutate the host tree.
20512087
nextEffect = firstEffect;
20522088
do {
@@ -2112,6 +2148,10 @@ function commitRootImpl(root, renderPriorityLevel) {
21122148

21132149
nextEffect = null;
21142150

2151+
if (enableProfilerNestedUpdateScheduledHook) {
2152+
rootCommittingMutationOrLayoutEffects = null;
2153+
}
2154+
21152155
// Tell Scheduler to yield at the end of the frame, so the browser has an
21162156
// opportunity to paint.
21172157
requestPaint();

0 commit comments

Comments
 (0)