Always reconcile against current children (#11564)
The new resuming algorithm will always reconcile against the current child set, even if there's a newer work-in-progress child set.
Andrew Clark committed
Nov 16, 2017 at 16:58 UTC
fd03a86429122c4e3cd4ec01db7552bd8391ad91
2 files changed
+19
-61
packages/react-reconciler/src/ReactChildFiber.js
+8
-32
@@ -13,7 +13,7 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
13
import type {ExpirationTime} from 'react-reconciler/src/ReactFiberExpirationTime';
14
15
import {enableReactFragment} from 'shared/ReactFeatureFlags';
16
-import {NoEffect, Placement, Deletion} from 'shared/ReactTypeOfSideEffect';
16
+import {Placement, Deletion} from 'shared/ReactTypeOfSideEffect';
17
import {
18
FunctionalComponent,
19
ClassComponent,
@@ -222,21 +222,12 @@ function warnOnFunctionType() {
222
// to be able to optimize each path individually by branching early. This needs
223
// a compiler or we can do it manually. Helpers that don't need this branching
224
// live outside of this function.
225
-function ChildReconciler(shouldClone, shouldTrackSideEffects) {
225
+function ChildReconciler(shouldTrackSideEffects) {
226
function deleteChild(returnFiber: Fiber, childToDelete: Fiber): void {
227
if (!shouldTrackSideEffects) {
228
// Noop.
229
return;
230
}
231
- if (!shouldClone) {
232
- // When we're reconciling in place we have a work in progress copy. We
233
- // actually want the current copy. If there is no current copy, then we
234
- // don't need to track deletion side-effects.
235
- if (childToDelete.alternate === null) {
236
- return;
237
- }
238
- childToDelete = childToDelete.alternate;
239
- }
231
// Deletions are added in reversed order so we add it to the front.
232
// At this point, the return fiber's effect list is empty except for
233
// deletions, so we can just append the deletion to the list. The remaining
@@ -300,22 +291,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
291
): Fiber {
292
// We currently set sibling to null and index to 0 here because it is easy
293
// to forget to do before returning it. E.g. for the single child case.
303
- if (shouldClone) {
304
- const clone = createWorkInProgress(fiber, pendingProps, expirationTime);
305
- clone.index = 0;
306
- clone.sibling = null;
307
- return clone;
308
- } else {
309
- // We override the expiration time even if it is earlier, because if
310
- // we're reconciling at a later time that means that this was
311
- // down-prioritized.
312
- fiber.expirationTime = expirationTime;
313
- fiber.effectTag = NoEffect;
314
- fiber.index = 0;
315
- fiber.sibling = null;
316
- fiber.pendingProps = pendingProps;
317
- return fiber;
318
- }
294
+ const clone = createWorkInProgress(fiber, pendingProps, expirationTime);
295
+ clone.index = 0;
296
+ clone.sibling = null;
297
+ return clone;
298
}
299
300
function placeChild(
@@ -1553,11 +1532,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1532
return reconcileChildFibers;
1533
}
1534
1556
-export const reconcileChildFibers = ChildReconciler(true, true);
1557
-
1558
-export const reconcileChildFibersInPlace = ChildReconciler(false, true);
1559
-
1560
-export const mountChildFibersInPlace = ChildReconciler(false, false);
1535
+export const reconcileChildFibers = ChildReconciler(true);
1536
+export const mountChildFibers = ChildReconciler(false);
1537
1538
export function cloneChildFibers(
1539
current: Fiber | null,
packages/react-reconciler/src/ReactFiberBeginWork.js
+11
-29
@@ -44,9 +44,8 @@ import {cancelWorkTimer} from './ReactDebugFiberPerf';
44
45
import ReactFiberClassComponent from './ReactFiberClassComponent';
46
import {
47
- mountChildFibersInPlace,
47
+ mountChildFibers,
48
reconcileChildFibers,
49
- reconcileChildFibersInPlace,
49
cloneChildFibers,
50
} from './ReactChildFiber';
51
import {processUpdateQueue} from './ReactFiberUpdateQueue';
@@ -119,13 +118,13 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
118
// won't update its child set by applying minimal side-effects. Instead,
119
// we will add them all to the child before it gets rendered. That means
120
// we can optimize this reconciliation pass by not tracking side-effects.
122
- workInProgress.child = mountChildFibersInPlace(
121
+ workInProgress.child = mountChildFibers(
122
workInProgress,
124
- workInProgress.child,
123
+ null,
124
nextChildren,
125
renderExpirationTime,
126
);
128
- } else if (current.child === workInProgress.child) {
127
+ } else {
128
// If the current child is the same as the work in progress, it means that
129
// we haven't yet started any work on these children. Therefore, we use
130
// the clone algorithm to create a copy of all the current children.
@@ -134,17 +133,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
133
// let's throw it out.
134
workInProgress.child = reconcileChildFibers(
135
workInProgress,
137
- workInProgress.child,
138
- nextChildren,
139
- renderExpirationTime,
140
- );
141
- } else {
142
- // If, on the other hand, it is already using a clone, that means we've
143
- // already begun some work on this tree and we can continue where we left
144
- // off by reconciling against the existing children.
145
- workInProgress.child = reconcileChildFibersInPlace(
146
- workInProgress,
147
- workInProgress.child,
136
+ current.child,
137
nextChildren,
138
renderExpirationTime,
139
);
@@ -355,9 +344,9 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
344
// Ensure that children mount into this root without tracking
345
// side-effects. This ensures that we don't store Placement effects on
346
// nodes that will be hydrated.
358
- workInProgress.child = mountChildFibersInPlace(
347
+ workInProgress.child = mountChildFibers(
348
workInProgress,
360
- workInProgress.child,
349
+ null,
350
element,
351
renderExpirationTime,
352
);
@@ -569,21 +558,14 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
558
// The following is a fork of reconcileChildrenAtExpirationTime but using
559
// stateNode to store the child.
560
if (current === null) {
572
- workInProgress.stateNode = mountChildFibersInPlace(
573
- workInProgress,
574
- workInProgress.stateNode,
575
- nextChildren,
576
- renderExpirationTime,
577
- );
578
- } else if (current.child === workInProgress.child) {
579
- workInProgress.stateNode = reconcileChildFibers(
561
+ workInProgress.stateNode = mountChildFibers(
562
workInProgress,
563
workInProgress.stateNode,
564
nextChildren,
565
renderExpirationTime,
566
);
567
} else {
586
- workInProgress.stateNode = reconcileChildFibersInPlace(
568
+ workInProgress.stateNode = reconcileChildFibers(
569
workInProgress,
570
workInProgress.stateNode,
571
nextChildren,
@@ -628,9 +610,9 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
610
// flow doesn't do during mount. This doesn't happen at the root because
611
// the root always starts with a "current" with a null child.
612
// TODO: Consider unifying this with how the root works.
631
- workInProgress.child = reconcileChildFibersInPlace(
613
+ workInProgress.child = reconcileChildFibers(
614
workInProgress,
633
- workInProgress.child,
615
+ null,
616
nextChildren,
617
renderExpirationTime,
618
);