Reset effect list when we recompute children

We only use the effect list when we reuse our progressed children.
Otherwise it needs to reset to null.

In all other branches, other than bailoutOnLowPriority, we
revisit the children which recreates this list.

We should also not add fibers to their own effect list since it
becomes difficult to perform work on self without touching the
children too. Nothing else does that neither.

Since that means that the root isn't added to an effect list we
need to special case the root.
This commit is contained in:
Sebastian Markbage 2016-10-06 19:17:26 -07:00 committed by Sebastian Markbåge
parent 1d437dc9ad
commit 43645a6586
3 changed files with 36 additions and 16 deletions

View File

@ -221,8 +221,9 @@ exports.cloneFiber = function(fiber : Fiber, priorityLevel : PriorityLevel) : Fi
// extra memory if needed.
let alt = fiber.alternate;
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.
// If we clone, then we do so from the "current" state. The current state
// can't have any side-effects that are still valid so we reset just to be
// sure.
alt.effectTag = NoEffect;
alt.nextEffect = null;
alt.firstEffect = null;

View File

@ -403,9 +403,15 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, g
function bailoutOnLowPriority(current, workInProgress) {
if (current) {
// TODO: If I have started work on this node, mark it as finished, then
// return do other work, come back and hit this node... we killed that
// work. It is now in an inconsistent state. We probably need to check
// progressedChild or something.
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.output = current.output;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
}
return null;
}
@ -416,6 +422,11 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, g
return bailoutOnLowPriority(current, workInProgress);
}
// If we don't bail out, we're going be recomputing our children so we need
// to drop our effect list.
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
if (workInProgress.progressedPriority === priorityLevel) {
// If we have progressed work on this priority level already, we can
// proceed this that as the child.

View File

@ -143,6 +143,13 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
effectfulFiber.nextEffect = null;
effectfulFiber = next;
}
// Finally if the root itself had an effect, we perform that since it is not
// part of the effect list.
if (finishedWork.effectTag !== NoEffect) {
const current = finishedWork.alternate;
commitWork(current, finishedWork);
}
}
function resetWorkPriority(workInProgress : Fiber) {
@ -179,20 +186,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
workInProgress.pendingProps = null;
workInProgress.updateQueue = null;
// If this fiber had side-effects, we append it to the end of its own
// effect list.
if (workInProgress.effectTag !== NoEffect) {
// Schedule a side-effect on this fiber, AFTER the children's
// side-effects. We can perform certain side-effects earlier if
// needed, by doing multiple passes over the effect list.
if (workInProgress.lastEffect) {
workInProgress.lastEffect.nextEffect = workInProgress;
} else {
workInProgress.firstEffect = workInProgress;
}
workInProgress.lastEffect = workInProgress;
}
const returnFiber = workInProgress.return;
if (returnFiber) {
@ -208,6 +201,21 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
}
returnFiber.lastEffect = workInProgress.lastEffect;
}
// If this fiber had side-effects, we append it AFTER the children's
// side-effects. We can perform certain side-effects earlier if
// needed, by doing multiple passes over the effect list. We don't want
// to schedule our own side-effect on our own list because if end up
// reusing children we'll schedule this effect onto itself since we're
// at the end.
if (workInProgress.effectTag !== NoEffect) {
if (returnFiber.lastEffect) {
returnFiber.lastEffect.nextEffect = workInProgress;
} else {
returnFiber.firstEffect = workInProgress;
}
returnFiber.lastEffect = workInProgress;
}
}
if (next) {