@samitouri / QOS-React / commits / 901691eb92

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 +};