Tag the fiber with the kind of side-effect that was applied to it
This allow us to track what kind of side-effect this was even though we only have a single linked list for all side-effects.
Sebastian Markbage committed
Oct 4, 2016 at 11:14 UTC
901691eb925fd58e20c93feea652ca479d1b4fa1
3 files changed
+55
-13
src/renderers/shared/fiber/ReactChildFiber.js
+22
-13
@@ -25,6 +25,7 @@ var {
25
var ReactFiber = require('ReactFiber');
26
var ReactPriorityLevel = require('ReactPriorityLevel');
27
var ReactReifiedYield = require('ReactReifiedYield');
28
+var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
29
var ReactTypeOfWork = require('ReactTypeOfWork');
30
31
var getIteratorFn = require('getIteratorFn');
@@ -56,6 +57,12 @@ const {
57
NoWork,
58
} = ReactPriorityLevel;
59
60
+const {
61
+ NoEffect,
62
+ Placement,
63
+ Deletion,
64
+} = ReactTypeOfSideEffect;
65
+
66
// This wrapper function exists because I expect to clone the code in each path
67
// to be able to optimize each path individually by branching early. This needs
68
// a compiler or we can do it manually. Helpers that don't need this branching
@@ -90,6 +97,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
97
childToDelete;
98
}
99
childToDelete.nextEffect = null;
100
+ childToDelete.effectTag = Deletion;
101
}
102
103
function deleteRemainingChildren(
@@ -145,6 +153,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
153
fiber.pendingWorkPriority > priority) {
154
fiber.pendingWorkPriority = priority;
155
}
156
+ fiber.effectTag = NoWork;
157
fiber.index = 0;
158
fiber.sibling = null;
159
return fiber;
@@ -162,7 +171,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
171
const oldIndex = current.index;
172
if (oldIndex < lastPlacedIndex) {
173
// This is a move.
165
- // TODO: Schedule a move side-effect for this child.
174
+ newFiber.effectTag = Placement;
175
return lastPlacedIndex;
176
} else {
177
// This item can stay in place.
@@ -170,7 +179,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
179
}
180
} else {
181
// This is an insertion.
173
- // TODO: Schedule an insertion side-effect for this child.
182
+ newFiber.effectTag = Placement;
183
return lastPlacedIndex;
184
}
185
}
@@ -207,7 +216,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
216
created.return = returnFiber;
217
return created;
218
} else {
210
- // Move based on index, TODO: This needs to restore a deletion marking.
219
+ // Move based on index
220
const existing = useFiber(current, priority);
221
existing.pendingProps = element.props;
222
existing.return = returnFiber;
@@ -228,7 +237,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
237
created.return = returnFiber;
238
return created;
239
} else {
231
- // Move based on index, TODO: This needs to restore a deletion marking.
240
+ // Move based on index
241
const existing = useFiber(current, priority);
242
existing.pendingProps = coroutine;
243
existing.return = returnFiber;
@@ -251,7 +260,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
260
created.return = returnFiber;
261
return created;
262
} else {
254
- // Move based on index, TODO: This needs to restore a deletion marking.
263
+ // Move based on index
264
const existing = useFiber(current, priority);
265
existing.output = createUpdatedReifiedYield(
266
current.output,
@@ -397,9 +406,6 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
406
priority : PriorityLevel
407
) : ?Fiber {
408
400
- // TODO: If this child matches, we need to undo the deletion. However,
401
- // we don't do that for the updateSlot case because nothing was deleted yet.
402
-
409
if (typeof newChild === 'string' || typeof newChild === 'number') {
410
// Text nodes doesn't have keys, so we neither have to check the old nor
411
// new node for the key. If both are text nodes, they match.
@@ -571,11 +577,15 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
577
}
578
579
if (shouldTrackSideEffects) {
574
- // Any existing children that we're consumed above were deleted. We need
580
+ // Any existing children that weren't consumed above were deleted. We need
581
// to add them to the deletion list.
582
existingChildren.forEach(child => deleteChild(returnFiber, child));
583
}
584
585
+ // TODO: Add deletions and insert/moves to the side-effect list.
586
+ // TODO: Clear the deletion list when we don't reconcile in place. When
587
+ // progressedChild isn't reused.
588
+
589
return resultingFirstChild;
590
}
591
@@ -718,10 +728,9 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
728
return created;
729
}
730
721
- // TODO: This API will tag the children with the side-effect of the
722
- // reconciliation itself. Deletes have to get added to the side-effect list
723
- // of the return fiber right now. Other side-effects will be added as we
724
- // pass through those children.
731
+ // This API will tag the children with the side-effect of the reconciliation
732
+ // itself. They will be added to the side-effect list as we pass through the
733
+ // children and the parent.
734
function reconcileChildFibers(
735
returnFiber : Fiber,
736
currentFirstChild : ?Fiber,
src/renderers/shared/fiber/ReactFiber.js
+10
@@ -15,6 +15,7 @@
15
import type { ReactFragment } from 'ReactTypes';
16
import type { ReactCoroutine, ReactYield } from 'ReactCoroutine';
17
import type { TypeOfWork } from 'ReactTypeOfWork';
18
+import type { TypeOfSideEffect } from 'ReactTypeOfSideEffect';
19
import type { PriorityLevel } from 'ReactPriorityLevel';
20
import type { UpdateQueue } from 'ReactFiberUpdateQueue';
21
@@ -34,6 +35,10 @@ var {
35
NoWork,
36
} = require('ReactPriorityLevel');
37
38
+var {
39
+ NoEffect,
40
+} = require('ReactTypeOfSideEffect');
41
+
42
// An Instance is shared between all versions of a component. We can easily
43
// break this out into a separate object to avoid copying so much to the
44
// alternate versions of the tree. We put this on a single object for now to
@@ -91,6 +96,9 @@ export type Fiber = Instance & {
96
// if this returns multiple values. Such as a fragment.
97
output: any, // This type will be more specific once we overload the tag.
98
99
+ // Effect
100
+ effectTag: TypeOfSideEffect,
101
+
102
// Singly linked list fast path to the next fiber with side-effects.
103
nextEffect: ?Fiber,
104
@@ -175,6 +183,7 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
183
callbackList: null,
184
output: null,
185
186
+ effectTag: NoEffect,
187
nextEffect: null,
188
firstEffect: null,
189
lastEffect: null,
@@ -214,6 +223,7 @@ exports.cloneFiber = function(fiber : Fiber, priorityLevel : PriorityLevel) : Fi
223
if (alt) {
224
// Whenever we clone, we do so to get a new work in progress.
225
// This ensures that we've reset these in the new tree.
226
+ alt.effectTag = NoEffect;
227
alt.nextEffect = null;
228
alt.firstEffect = null;
229
alt.lastEffect = null;
src/renderers/shared/fiber/ReactTypeOfSideEffect.js
new
+23
@@ -0,0 +1,23 @@
1
+/**
2
+ * Copyright 2013-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactTypeOfSideEffect
10
+ * @flow
11
+ */
12
+
13
+'use strict';
14
+
15
+export type TypeOfSideEffect = 0 | 1 | 2 | 3 | 4;
16
+
17
+module.exports = {
18
+ NoEffect: 0,
19
+ Placement: 1,
20
+ Update: 2,
21
+ PlacementAndUpdate: 3,
22
+ Deletion: 4,
23
+};