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.
This commit is contained in:
Sebastian Markbage
2016-10-17 16:17:30 -04:00
committed by Sebastian Markbåge
parent e9e645a9b1
commit 901691eb92
3 changed files with 55 additions and 13 deletions
+22 -13
View File
@@ -25,6 +25,7 @@ var {
var ReactFiber = require('ReactFiber');
var ReactPriorityLevel = require('ReactPriorityLevel');
var ReactReifiedYield = require('ReactReifiedYield');
var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
var ReactTypeOfWork = require('ReactTypeOfWork');
var getIteratorFn = require('getIteratorFn');
@@ -56,6 +57,12 @@ const {
NoWork,
} = ReactPriorityLevel;
const {
NoEffect,
Placement,
Deletion,
} = ReactTypeOfSideEffect;
// This wrapper function exists because I expect to clone the code in each path
// to be able to optimize each path individually by branching early. This needs
// a compiler or we can do it manually. Helpers that don't need this branching
@@ -90,6 +97,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
childToDelete;
}
childToDelete.nextEffect = null;
childToDelete.effectTag = Deletion;
}
function deleteRemainingChildren(
@@ -145,6 +153,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
fiber.pendingWorkPriority > priority) {
fiber.pendingWorkPriority = priority;
}
fiber.effectTag = NoWork;
fiber.index = 0;
fiber.sibling = null;
return fiber;
@@ -162,7 +171,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
const oldIndex = current.index;
if (oldIndex < lastPlacedIndex) {
// This is a move.
// TODO: Schedule a move side-effect for this child.
newFiber.effectTag = Placement;
return lastPlacedIndex;
} else {
// This item can stay in place.
@@ -170,7 +179,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
}
} else {
// This is an insertion.
// TODO: Schedule an insertion side-effect for this child.
newFiber.effectTag = Placement;
return lastPlacedIndex;
}
}
@@ -207,7 +216,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
created.return = returnFiber;
return created;
} else {
// Move based on index, TODO: This needs to restore a deletion marking.
// Move based on index
const existing = useFiber(current, priority);
existing.pendingProps = element.props;
existing.return = returnFiber;
@@ -228,7 +237,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
created.return = returnFiber;
return created;
} else {
// Move based on index, TODO: This needs to restore a deletion marking.
// Move based on index
const existing = useFiber(current, priority);
existing.pendingProps = coroutine;
existing.return = returnFiber;
@@ -251,7 +260,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
created.return = returnFiber;
return created;
} else {
// Move based on index, TODO: This needs to restore a deletion marking.
// Move based on index
const existing = useFiber(current, priority);
existing.output = createUpdatedReifiedYield(
current.output,
@@ -397,9 +406,6 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
priority : PriorityLevel
) : ?Fiber {
// TODO: If this child matches, we need to undo the deletion. However,
// we don't do that for the updateSlot case because nothing was deleted yet.
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes doesn't have keys, so we neither have to check the old nor
// new node for the key. If both are text nodes, they match.
@@ -571,11 +577,15 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
}
if (shouldTrackSideEffects) {
// Any existing children that we're consumed above were deleted. We need
// Any existing children that weren't consumed above were deleted. We need
// to add them to the deletion list.
existingChildren.forEach(child => deleteChild(returnFiber, child));
}
// TODO: Add deletions and insert/moves to the side-effect list.
// TODO: Clear the deletion list when we don't reconcile in place. When
// progressedChild isn't reused.
return resultingFirstChild;
}
@@ -718,10 +728,9 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
return created;
}
// TODO: This API will tag the children with the side-effect of the
// reconciliation itself. Deletes have to get added to the side-effect list
// of the return fiber right now. Other side-effects will be added as we
// pass through those children.
// This API will tag the children with the side-effect of the reconciliation
// itself. They will be added to the side-effect list as we pass through the
// children and the parent.
function reconcileChildFibers(
returnFiber : Fiber,
currentFirstChild : ?Fiber,
+10
View File
@@ -15,6 +15,7 @@
import type { ReactFragment } from 'ReactTypes';
import type { ReactCoroutine, ReactYield } from 'ReactCoroutine';
import type { TypeOfWork } from 'ReactTypeOfWork';
import type { TypeOfSideEffect } from 'ReactTypeOfSideEffect';
import type { PriorityLevel } from 'ReactPriorityLevel';
import type { UpdateQueue } from 'ReactFiberUpdateQueue';
@@ -34,6 +35,10 @@ var {
NoWork,
} = require('ReactPriorityLevel');
var {
NoEffect,
} = require('ReactTypeOfSideEffect');
// An Instance is shared between all versions of a component. We can easily
// break this out into a separate object to avoid copying so much to the
// alternate versions of the tree. We put this on a single object for now to
@@ -91,6 +96,9 @@ export type Fiber = Instance & {
// if this returns multiple values. Such as a fragment.
output: any, // This type will be more specific once we overload the tag.
// Effect
effectTag: TypeOfSideEffect,
// Singly linked list fast path to the next fiber with side-effects.
nextEffect: ?Fiber,
@@ -175,6 +183,7 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
callbackList: null,
output: null,
effectTag: NoEffect,
nextEffect: null,
firstEffect: null,
lastEffect: null,
@@ -214,6 +223,7 @@ exports.cloneFiber = function(fiber : Fiber, priorityLevel : PriorityLevel) : Fi
if (alt) {
// Whenever we clone, we do so to get a new work in progress.
// This ensures that we've reset these in the new tree.
alt.effectTag = NoEffect;
alt.nextEffect = null;
alt.firstEffect = null;
alt.lastEffect = null;
@@ -0,0 +1,23 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactTypeOfSideEffect
* @flow
*/
'use strict';
export type TypeOfSideEffect = 0 | 1 | 2 | 3 | 4;
module.exports = {
NoEffect: 0,
Placement: 1,
Update: 2,
PlacementAndUpdate: 3,
Deletion: 4,
};