Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dec061d

Browse files
committedJul 24, 2020
Move Persistent Mode Optimization away from firstEffect
Persistent mode needs to clone a parent and add its children if a child has changed. We have an optimization in persistent mode where we don't do that if no child could've changed. If there are no effects scheduled for any child then there couldn't have been changes. Instead of checking for this on firstEffect, we now check this on the children's effectTag and subtreeTags. This is quite unfortunate because if we could just do this check a little bit later we would've already gotten it transferred to the completed work's subtreeTag. Now we have to loop over all the children and if any of them changed, we have to loop over them again. Doing at least two loops per parent.
1 parent 909b612 commit dec061d

File tree

1 file changed

+28
-7
lines changed

1 file changed

+28
-7
lines changed
 

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

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ import {
6565
NoEffect,
6666
DidCapture,
6767
Snapshot,
68+
MutationMask,
6869
} from './ReactSideEffectTags';
70+
import {NoEffect as NoSubtreeTag, Mutation} from './ReactSubtreeTags';
6971
import invariant from 'shared/invariant';
7072

7173
import {
@@ -154,6 +156,25 @@ function markRef(workInProgress: Fiber) {
154156
workInProgress.effectTag |= Ref;
155157
}
156158

159+
function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {
160+
const didBailout = current !== null && current.child === completedWork.child;
161+
if (didBailout) {
162+
return true;
163+
}
164+
165+
let child = completedWork.child;
166+
while (child !== null) {
167+
if ((child.effectTag & MutationMask) !== NoEffect) {
168+
return false;
169+
}
170+
if ((child.subtreeTag & Mutation) !== NoSubtreeTag) {
171+
return false;
172+
}
173+
child = child.sibling;
174+
}
175+
return true;
176+
}
177+
157178
let appendAllChildren;
158179
let updateHostContainer;
159180
let updateHostComponent;
@@ -198,7 +219,7 @@ if (supportsMutation) {
198219
}
199220
};
200221

201-
updateHostContainer = function(workInProgress: Fiber) {
222+
updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {
202223
// Noop
203224
};
204225
updateHostComponent = function(
@@ -442,13 +463,13 @@ if (supportsMutation) {
442463
node = node.sibling;
443464
}
444465
};
445-
updateHostContainer = function(workInProgress: Fiber) {
466+
updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {
446467
const portalOrRoot: {
447468
containerInfo: Container,
448469
pendingChildren: ChildSet,
449470
...
450471
} = workInProgress.stateNode;
451-
const childrenUnchanged = workInProgress.firstEffect === null;
472+
const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);
452473
if (childrenUnchanged) {
453474
// No changes, just reuse the existing instance.
454475
} else {
@@ -473,7 +494,7 @@ if (supportsMutation) {
473494
const oldProps = current.memoizedProps;
474495
// If there are no effects associated with this node, then none of our children had any updates.
475496
// This guarantees that we can reuse all of them.
476-
const childrenUnchanged = workInProgress.firstEffect === null;
497+
const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);
477498
if (childrenUnchanged && oldProps === newProps) {
478499
// No changes, just reuse the existing instance.
479500
// Note that this might release a previous clone.
@@ -556,7 +577,7 @@ if (supportsMutation) {
556577
};
557578
} else {
558579
// No host operations
559-
updateHostContainer = function(workInProgress: Fiber) {
580+
updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {
560581
// Noop
561582
};
562583
updateHostComponent = function(
@@ -700,7 +721,7 @@ function completeWork(
700721
workInProgress.effectTag |= Snapshot;
701722
}
702723
}
703-
updateHostContainer(workInProgress);
724+
updateHostContainer(current, workInProgress);
704725
return null;
705726
}
706727
case HostComponent: {
@@ -979,7 +1000,7 @@ function completeWork(
9791000
}
9801001
case HostPortal:
9811002
popHostContainer(workInProgress);
982-
updateHostContainer(workInProgress);
1003+
updateHostContainer(current, workInProgress);
9831004
if (current === null) {
9841005
preparePortalMount(workInProgress.stateNode.containerInfo);
9851006
}

0 commit comments

Comments
 (0)
Please sign in to comment.