Skip to content

Commit feffd94

Browse files
author
Brian Vaughn
committed
Profiler onRender only called when we do work
If we didn't perform any work in the subtree, skip calling onRender.
1 parent fbb0375 commit feffd94

File tree

4 files changed

+54
-28
lines changed

4 files changed

+54
-28
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,9 @@ function updateHostComponent(
11481148
workInProgress.flags |= ContentReset;
11491149
}
11501150

1151+
// React DevTools reads this flag.
1152+
workInProgress.flags |= PerformedWork;
1153+
11511154
markRef(current, workInProgress);
11521155
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
11531156
return workInProgress.child;

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ import {
7777
LayoutMask,
7878
PassiveMask,
7979
StaticMask,
80+
PerformedWork,
8081
} from './ReactFiberFlags';
8182
import invariant from 'shared/invariant';
8283

@@ -987,9 +988,13 @@ function completeWork(
987988
const flags = workInProgress.flags;
988989
let newFlags = flags;
989990

990-
// Call onRender any time this fiber or its subtree are worked on, even
991-
// if there are no effects
992-
newFlags |= OnRenderFlag;
991+
// Call onRender any time this fiber or its subtree are worked on.
992+
if (
993+
(flags & PerformedWork) !== NoFlags ||
994+
(subtreeFlags & PerformedWork) !== NoFlags
995+
) {
996+
newFlags |= OnRenderFlag;
997+
}
993998

994999
// Call onCommit only if the subtree contains layout work, or if it
9951000
// contains deletions, since those might result in unmount work, which

packages/react/src/__tests__/ReactDOMTracing-test.internal.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,17 @@ describe('ReactDOMTracing', () => {
151151
expect(
152152
onInteractionScheduledWorkCompleted,
153153
).toHaveBeenLastNotifiedOfInteraction(interaction);
154-
// TODO: This is 4 instead of 3 because this update was scheduled at
155-
// idle priority, and idle updates are slightly higher priority than
156-
// offscreen work. So it takes two render passes to finish it. Profiler
157-
// calls `onRender` for the first render even though everything
158-
// bails out.
159-
expect(onRender).toHaveBeenCalledTimes(4);
154+
155+
if (gate(flags => flags.new)) {
156+
expect(onRender).toHaveBeenCalledTimes(3);
157+
} else {
158+
// TODO: This is 4 instead of 3 because this update was scheduled at
159+
// idle priority, and idle updates are slightly higher priority than
160+
// offscreen work. So it takes two render passes to finish it. Profiler
161+
// calls `onRender` for the first render even though everything
162+
// bails out.
163+
expect(onRender).toHaveBeenCalledTimes(4);
164+
}
160165
expect(onRender).toHaveLastRenderedWithInteractions(
161166
new Set([interaction]),
162167
);
@@ -305,12 +310,16 @@ describe('ReactDOMTracing', () => {
305310
expect(
306311
onInteractionScheduledWorkCompleted,
307312
).toHaveBeenLastNotifiedOfInteraction(interaction);
308-
// TODO: This is 4 instead of 3 because this update was scheduled at
309-
// idle priority, and idle updates are slightly higher priority than
310-
// offscreen work. So it takes two render passes to finish it. Profiler
311-
// calls `onRender` for the first render even though everything
312-
// bails out.
313-
expect(onRender).toHaveBeenCalledTimes(4);
313+
if (gate(flags => flags.new)) {
314+
expect(onRender).toHaveBeenCalledTimes(3);
315+
} else {
316+
// TODO: This is 4 instead of 3 because this update was scheduled at
317+
// idle priority, and idle updates are slightly higher priority than
318+
// offscreen work. So it takes two render passes to finish it. Profiler
319+
// calls `onRender` for the first render even though everything
320+
// bails out.
321+
expect(onRender).toHaveBeenCalledTimes(4);
322+
}
314323
expect(onRender).toHaveLastRenderedWithInteractions(
315324
new Set([interaction]),
316325
);

packages/react/src/__tests__/ReactProfiler-test.internal.js

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -362,24 +362,33 @@ describe('Profiler', () => {
362362

363363
Scheduler.unstable_advanceTime(20); // 10 -> 30
364364

365-
// Updating a parent should report a re-render,
366-
// since React technically did a little bit of work between the Profiler and the bailed out subtree.
367365
renderer.update(<App />);
368366

369-
expect(callback).toHaveBeenCalledTimes(1);
367+
if (gate(flags => flags.new)) {
368+
// None of the Profiler's subtree was rendered because App bailed out before the Profiler.
369+
// So we expect onRender not to be called.
370+
expect(callback).not.toHaveBeenCalled();
371+
} else {
372+
// Updating a parent reports a re-render,
373+
// since React technically did a little bit of work between the Profiler and the bailed out subtree.
374+
// This is not optimal but it's how the old reconciler fork works.
375+
expect(callback).toHaveBeenCalledTimes(1);
370376

371-
call = callback.mock.calls[0];
377+
call = callback.mock.calls[0];
372378

373-
expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6);
374-
expect(call[0]).toBe('test');
375-
expect(call[1]).toBe('update');
376-
expect(call[2]).toBe(0); // actual time
377-
expect(call[3]).toBe(10); // base time
378-
expect(call[4]).toBe(30); // start time
379-
expect(call[5]).toBe(30); // commit time
380-
expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events
379+
expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6);
380+
expect(call[0]).toBe('test');
381+
expect(call[1]).toBe('update');
382+
expect(call[2]).toBe(0); // actual time
383+
expect(call[3]).toBe(10); // base time
384+
expect(call[4]).toBe(30); // start time
385+
expect(call[5]).toBe(30); // commit time
386+
expect(call[6]).toEqual(
387+
enableSchedulerTracing ? new Set() : undefined,
388+
); // interaction events
381389

382-
callback.mockReset();
390+
callback.mockReset();
391+
}
383392

384393
Scheduler.unstable_advanceTime(20); // 30 -> 50
385394

0 commit comments

Comments
 (0)