diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js index dbbb9146695..67caa03ad51 100644 --- a/src/renderers/shared/fiber/ReactFiberBeginWork.js +++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js @@ -518,11 +518,49 @@ module.exports = function( } else if (nextCoroutine === null || workInProgress.memoizedProps === nextCoroutine) { return bailoutOnAlreadyFinishedWork(current, workInProgress); } - reconcileChildren(current, workInProgress, nextCoroutine.children); + + const nextChildren = nextCoroutine.children; + const priorityLevel = workInProgress.pendingWorkPriority; + + // The following is a fork of reconcileChildrenAtPriority but using + // stateNode to store the child. + + // At this point any memoization is no longer valid since we'll have changed + // the children. + workInProgress.memoizedProps = null; + if (!current) { + workInProgress.stateNode = mountChildFibersInPlace( + workInProgress, + workInProgress.stateNode, + nextChildren, + priorityLevel + ); + } else if (current.child === workInProgress.child) { + clearDeletions(workInProgress); + + workInProgress.stateNode = reconcileChildFibers( + workInProgress, + workInProgress.stateNode, + nextChildren, + priorityLevel + ); + + transferDeletions(workInProgress); + } else { + workInProgress.stateNode = reconcileChildFibersInPlace( + workInProgress, + workInProgress.stateNode, + nextChildren, + priorityLevel + ); + + transferDeletions(workInProgress); + } + memoizeProps(workInProgress, nextCoroutine); // This doesn't take arbitrary time so we could synchronously just begin // eagerly do the work of workInProgress.child as an optimization. - return workInProgress.child; + return workInProgress.stateNode; } function updatePortalComponent(current, workInProgress) { diff --git a/src/renderers/shared/fiber/ReactFiberCommitWork.js b/src/renderers/shared/fiber/ReactFiberCommitWork.js index 37bef63964c..0dd429cdda1 100644 --- a/src/renderers/shared/fiber/ReactFiberCommitWork.js +++ b/src/renderers/shared/fiber/ReactFiberCommitWork.js @@ -136,7 +136,6 @@ module.exports = function( while (node.tag !== HostComponent && node.tag !== HostText) { // If it is not host node and, we might have a host node inside it. // Try to search down until we find one. - // TODO: For coroutines, this will have to search the stateNode. if (node.effectTag & Placement) { // If we don't have a child, try the siblings instead. continue siblings; @@ -198,7 +197,6 @@ module.exports = function( // down its children. Instead, we'll get insertions from each child in // the portal directly. } else if (node.child) { - // TODO: Coroutines need to visit the stateNode. node.child.return = node; node = node.child; continue; @@ -229,7 +227,6 @@ module.exports = function( // Visit children because they may contain more composite or host nodes. // Skip portals because commitUnmount() currently visits them recursively. if (node.child && node.tag !== HostPortal) { - // TODO: Coroutines need to visit the stateNode. node.child.return = node; node = node.child; continue; @@ -273,7 +270,6 @@ module.exports = function( commitUnmount(node); // Visit children because we may find more host components below. if (node.child) { - // TODO: Coroutines need to visit the stateNode. node.child.return = node; node = node.child; continue; diff --git a/src/renderers/shared/fiber/ReactFiberCompleteWork.js b/src/renderers/shared/fiber/ReactFiberCompleteWork.js index 776db30ecc0..08644759ca0 100644 --- a/src/renderers/shared/fiber/ReactFiberCompleteWork.js +++ b/src/renderers/shared/fiber/ReactFiberCompleteWork.js @@ -66,6 +66,18 @@ module.exports = function( popHostContainer, } = hostContext; + function markChildAsProgressed(current, workInProgress, priorityLevel) { + // We now have clones. Let's store them as the currently progressed work. + workInProgress.progressedChild = workInProgress.child; + workInProgress.progressedPriority = priorityLevel; + if (current) { + // We also store it on the current. When the alternate swaps in we can + // continue from this point. + current.progressedChild = workInProgress.progressedChild; + current.progressedPriority = workInProgress.progressedPriority; + } + } + function markUpdate(workInProgress : Fiber) { // Tag the fiber with an update effect. This turns a Placement into // an UpdateAndPlacement. @@ -73,7 +85,7 @@ module.exports = function( } function appendAllYields(yields : Array, workInProgress : Fiber) { - let node = workInProgress.child; + let node = workInProgress.stateNode; while (node) { if (node.tag === HostComponent || node.tag === HostText || node.tag === HostPortal) { @@ -81,7 +93,6 @@ module.exports = function( } else if (node.tag === YieldComponent) { yields.push(node.type); } else if (node.child) { - // TODO: Coroutines need to visit the stateNode. node.child.return = node; node = node.child; continue; @@ -123,16 +134,17 @@ module.exports = function( var props = coroutine.props; var nextChildren = fn(props, yields); - var currentFirstChild = current ? current.stateNode : null; + var currentFirstChild = current ? current.child : null; // Inherit the priority of the returnFiber. const priority = workInProgress.pendingWorkPriority; - workInProgress.stateNode = reconcileChildFibers( + workInProgress.child = reconcileChildFibers( workInProgress, currentFirstChild, nextChildren, priority ); - return workInProgress.stateNode; + markChildAsProgressed(current, workInProgress, priority); + return workInProgress.child; } function appendAllChildren(parent : I, workInProgress : Fiber) { @@ -147,7 +159,6 @@ module.exports = function( // down its children. Instead, we'll get insertions from each child in // the portal directly. } else if (node.child) { - // TODO: Coroutines need to visit the stateNode. node = node.child; continue; } diff --git a/src/renderers/shared/fiber/ReactFiberScheduler.js b/src/renderers/shared/fiber/ReactFiberScheduler.js index 773ac5c83a2..f2f95d41cfb 100644 --- a/src/renderers/shared/fiber/ReactFiberScheduler.js +++ b/src/renderers/shared/fiber/ReactFiberScheduler.js @@ -434,6 +434,8 @@ module.exports = function(config : HostConfig { expect(ops).toEqual([ 'Unmount Parent', - // TODO: This should happen in the order Child, Continuation which it - // will once we swap stateNode and child positions of these. - 'Unmount Continuation', 'Unmount Child', + 'Unmount Continuation', ]); }); diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index 1a393d426b2..7a01f13cb7c 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -97,7 +97,6 @@ function findAllInRenderedFiberTreeInternal(fiber, test) { } } if (node.child) { - // TODO: Coroutines need to visit the stateNode. node.child.return = node; node = node.child; continue;