diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js index 6958ea33ee..08e47b43ba 100644 --- a/src/renderers/shared/fiber/ReactChildFiber.js +++ b/src/renderers/shared/fiber/ReactChildFiber.js @@ -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, diff --git a/src/renderers/shared/fiber/ReactFiber.js b/src/renderers/shared/fiber/ReactFiber.js index 40f447b562..d9e049f7f8 100644 --- a/src/renderers/shared/fiber/ReactFiber.js +++ b/src/renderers/shared/fiber/ReactFiber.js @@ -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; diff --git a/src/renderers/shared/fiber/ReactTypeOfSideEffect.js b/src/renderers/shared/fiber/ReactTypeOfSideEffect.js new file mode 100644 index 0000000000..55a9cabc42 --- /dev/null +++ b/src/renderers/shared/fiber/ReactTypeOfSideEffect.js @@ -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, +};