Skip to content

Commit 81aaee5

Browse files
acdliteBrian Vaughn
and
Brian Vaughn
authored
Don't call onCommit et al if there are no effects (#19863)
* Don't call onCommit et al if there are no effects Checks `subtreeFlags` before scheduling an effect on the Profiler. * Fix failing Profiler tests The change to conditionally call Profiler commit hooks only if updates were scheduled broke a few of the Profiler tests. I've fixed the tests by either: * Adding a no-op passive effect into the subtree or * Converting onPostCommit to onCommit When possible, I opted to add the no-op passive effect to the tests since that that hook is called later (during passive phase) so the test is a little broader. In a few cases, this required adding awkward act() wrappers so I opted to go with onCommit instead. Co-authored-by: Brian Vaughn <bvaughn@fb.com>
1 parent 7355bf5 commit 81aaee5

File tree

4 files changed

+795
-714
lines changed

4 files changed

+795
-714
lines changed

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

-15
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ import {
6060
Hydrating,
6161
ContentReset,
6262
DidCapture,
63-
Update,
64-
Passive,
6563
Ref,
6664
Deletion,
6765
ForceUpdateForLegacySuspense,
@@ -675,9 +673,6 @@ function updateProfiler(
675673
renderLanes: Lanes,
676674
) {
677675
if (enableProfilerTimer) {
678-
// TODO: Only call onRender et al if subtree has effects
679-
workInProgress.flags |= Update | Passive;
680-
681676
// Reset effect durations for the next eventual effect phase.
682677
// These are reset during render to allow the DevTools commit hook a chance to read them,
683678
const stateNode = workInProgress.stateNode;
@@ -3117,16 +3112,6 @@ function beginWork(
31173112
}
31183113
case Profiler:
31193114
if (enableProfilerTimer) {
3120-
// Profiler should only call onRender when one of its descendants actually rendered.
3121-
// TODO: Only call onRender et al if subtree has effects
3122-
const hasChildWork = includesSomeLane(
3123-
renderLanes,
3124-
workInProgress.childLanes,
3125-
);
3126-
if (hasChildWork) {
3127-
workInProgress.flags |= Passive | Update;
3128-
}
3129-
31303115
// Reset effect durations for the next eventual effect phase.
31313116
// These are reset during render to allow the DevTools commit hook a chance to read them,
31323117
const stateNode = workInProgress.stateNode;

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import {
6868
Placement,
6969
Snapshot,
7070
Update,
71+
Callback,
7172
PassiveMask,
7273
} from './ReactFiberFlags';
7374
import getComponentName from 'shared/getComponentName';
@@ -676,10 +677,17 @@ function commitLifeCycles(
676677
if (enableProfilerTimer) {
677678
const {onCommit, onRender} = finishedWork.memoizedProps;
678679
const {effectDuration} = finishedWork.stateNode;
680+
const flags = finishedWork.flags;
679681

680682
const commitTime = getCommitTime();
681683

682-
if (typeof onRender === 'function') {
684+
const OnRenderFlag = Update;
685+
const OnCommitFlag = Callback;
686+
687+
if (
688+
(flags & OnRenderFlag) !== NoFlags &&
689+
typeof onRender === 'function'
690+
) {
683691
if (enableSchedulerTracing) {
684692
onRender(
685693
finishedWork.memoizedProps.id,
@@ -703,7 +711,10 @@ function commitLifeCycles(
703711
}
704712

705713
if (enableProfilerCommitHooks) {
706-
if (typeof onCommit === 'function') {
714+
if (
715+
(flags & OnCommitFlag) !== NoFlags &&
716+
typeof onCommit === 'function'
717+
) {
707718
if (enableSchedulerTracing) {
708719
onCommit(
709720
finishedWork.memoizedProps.id,

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

+54-1
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,15 @@ import {
6767
import {
6868
Ref,
6969
Update,
70+
Callback,
71+
Passive,
72+
Deletion,
7073
NoFlags,
7174
DidCapture,
7275
Snapshot,
7376
MutationMask,
77+
LayoutMask,
78+
PassiveMask,
7479
StaticMask,
7580
} from './ReactFiberFlags';
7681
import invariant from 'shared/invariant';
@@ -787,6 +792,8 @@ function bubbleProperties(completedWork: Fiber) {
787792
}
788793

789794
completedWork.childLanes = newChildLanes;
795+
796+
return didBailout;
790797
}
791798

792799
function completeWork(
@@ -804,7 +811,6 @@ function completeWork(
804811
case ForwardRef:
805812
case Fragment:
806813
case Mode:
807-
case Profiler:
808814
case ContextConsumer:
809815
case MemoComponent:
810816
bubbleProperties(workInProgress);
@@ -966,6 +972,53 @@ function completeWork(
966972
bubbleProperties(workInProgress);
967973
return null;
968974
}
975+
case Profiler: {
976+
const didBailout = bubbleProperties(workInProgress);
977+
if (!didBailout) {
978+
// Use subtreeFlags to determine which commit callbacks should fire.
979+
// TODO: Move this logic to the commit phase, since we already check if
980+
// a fiber's subtree contains effects. Refactor the commit phase's
981+
// depth-first traversal so that we can put work tag-specific logic
982+
// before or after committing a subtree's effects.
983+
const OnRenderFlag = Update;
984+
const OnCommitFlag = Callback;
985+
const OnPostCommitFlag = Passive;
986+
const subtreeFlags = workInProgress.subtreeFlags;
987+
const flags = workInProgress.flags;
988+
let newFlags = flags;
989+
990+
// Call onRender any time this fiber or its subtree are worked on, even
991+
// if there are no effects
992+
newFlags |= OnRenderFlag;
993+
994+
// Call onCommit only if the subtree contains layout work, or if it
995+
// contains deletions, since those might result in unmount work, which
996+
// we include in the same measure.
997+
// TODO: Can optimize by using a static flag to track whether a tree
998+
// contains layout effects, like we do for passive effects.
999+
if (
1000+
(flags & (LayoutMask | Deletion)) !== NoFlags ||
1001+
(subtreeFlags & (LayoutMask | Deletion)) !== NoFlags
1002+
) {
1003+
newFlags |= OnCommitFlag;
1004+
}
1005+
1006+
// Call onPostCommit only if the subtree contains passive work.
1007+
// Don't have to check for deletions, because Deletion is already
1008+
// a passive flag.
1009+
if (
1010+
(flags & PassiveMask) !== NoFlags ||
1011+
(subtreeFlags & PassiveMask) !== NoFlags
1012+
) {
1013+
newFlags |= OnPostCommitFlag;
1014+
}
1015+
workInProgress.flags = newFlags;
1016+
} else {
1017+
// This fiber and its subtree bailed out, so don't fire any callbacks.
1018+
}
1019+
1020+
return null;
1021+
}
9691022
case SuspenseComponent: {
9701023
popSuspenseContext(workInProgress);
9711024
const nextState: null | SuspenseState = workInProgress.memoizedState;

0 commit comments

Comments
 (0)