Skip to content

Commit

Permalink
moved mutation code to passive (#24251)
Browse files Browse the repository at this point in the history
This PR moves the code for transition tracing in the mutation phase that adds transitions to the pending callbacks object (to be called sometime later after paint) from the mutation to the passive phase.

Things to think about:

Passive effects can be flushed before or after paint. How do we make sure that we get the correct end time for the interaction?
  • Loading branch information
lunaruan committed Apr 8, 2022
1 parent 5b2e725 commit 4ebaeae
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 104 deletions.
63 changes: 33 additions & 30 deletions packages/react-reconciler/src/ReactFiberCommitWork.new.js
Expand Up @@ -2227,32 +2227,6 @@ function commitMutationEffectsOnFiber(
// because of the shared reconciliation logic below.
const flags = finishedWork.flags;

if (enableTransitionTracing) {
switch (finishedWork.tag) {
case HostRoot: {
const state = finishedWork.memoizedState;
const transitions = state.transitions;
if (transitions !== null) {
transitions.forEach(transition => {
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
addTransitionStartCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});

addTransitionCompleteCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});
});

clearTransitionsForLanes(root, lanes);
state.transitions = null;
}
}
}
}

if (flags & ContentReset) {
commitResetTextContent(finishedWork);
}
Expand Down Expand Up @@ -2639,34 +2613,41 @@ function reappearLayoutEffects_complete(subtreeRoot: Fiber) {
export function commitPassiveMountEffects(
root: FiberRoot,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
nextEffect = finishedWork;
commitPassiveMountEffects_begin(finishedWork, root);
commitPassiveMountEffects_begin(finishedWork, root, committedLanes);
}

function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
function commitPassiveMountEffects_begin(
subtreeRoot: Fiber,
root: FiberRoot,
committedLanes: Lanes,
) {
while (nextEffect !== null) {
const fiber = nextEffect;
const firstChild = fiber.child;
if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {
ensureCorrectReturnPointer(firstChild, fiber);
nextEffect = firstChild;
} else {
commitPassiveMountEffects_complete(subtreeRoot, root);
commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes);
}
}
}

function commitPassiveMountEffects_complete(
subtreeRoot: Fiber,
root: FiberRoot,
committedLanes: Lanes,
) {
while (nextEffect !== null) {
const fiber = nextEffect;

if ((fiber.flags & Passive) !== NoFlags) {
setCurrentDebugFiberInDEV(fiber);
try {
commitPassiveMountOnFiber(root, fiber);
commitPassiveMountOnFiber(root, fiber, committedLanes);
} catch (error) {
reportUncaughtErrorInDEV(error);
captureCommitPhaseError(fiber, fiber.return, error);
Expand All @@ -2693,6 +2674,7 @@ function commitPassiveMountEffects_complete(
function commitPassiveMountOnFiber(
finishedRoot: FiberRoot,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
switch (finishedWork.tag) {
case FunctionComponent:
Expand Down Expand Up @@ -2734,6 +2716,27 @@ function commitPassiveMountOnFiber(
}
}
}

if (enableTransitionTracing) {
const transitions = finishedWork.memoizedState.transitions;
if (transitions !== null) {
transitions.forEach(transition => {
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
addTransitionStartCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});

addTransitionCompleteCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});
});

clearTransitionsForLanes(finishedRoot, committedLanes);
finishedWork.memoizedState.transitions = null;
}
}
break;
}
case LegacyHiddenComponent:
Expand Down
63 changes: 33 additions & 30 deletions packages/react-reconciler/src/ReactFiberCommitWork.old.js
Expand Up @@ -2227,32 +2227,6 @@ function commitMutationEffectsOnFiber(
// because of the shared reconciliation logic below.
const flags = finishedWork.flags;

if (enableTransitionTracing) {
switch (finishedWork.tag) {
case HostRoot: {
const state = finishedWork.memoizedState;
const transitions = state.transitions;
if (transitions !== null) {
transitions.forEach(transition => {
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
addTransitionStartCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});

addTransitionCompleteCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});
});

clearTransitionsForLanes(root, lanes);
state.transitions = null;
}
}
}
}

if (flags & ContentReset) {
commitResetTextContent(finishedWork);
}
Expand Down Expand Up @@ -2639,34 +2613,41 @@ function reappearLayoutEffects_complete(subtreeRoot: Fiber) {
export function commitPassiveMountEffects(
root: FiberRoot,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
nextEffect = finishedWork;
commitPassiveMountEffects_begin(finishedWork, root);
commitPassiveMountEffects_begin(finishedWork, root, committedLanes);
}

function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
function commitPassiveMountEffects_begin(
subtreeRoot: Fiber,
root: FiberRoot,
committedLanes: Lanes,
) {
while (nextEffect !== null) {
const fiber = nextEffect;
const firstChild = fiber.child;
if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {
ensureCorrectReturnPointer(firstChild, fiber);
nextEffect = firstChild;
} else {
commitPassiveMountEffects_complete(subtreeRoot, root);
commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes);
}
}
}

function commitPassiveMountEffects_complete(
subtreeRoot: Fiber,
root: FiberRoot,
committedLanes: Lanes,
) {
while (nextEffect !== null) {
const fiber = nextEffect;

if ((fiber.flags & Passive) !== NoFlags) {
setCurrentDebugFiberInDEV(fiber);
try {
commitPassiveMountOnFiber(root, fiber);
commitPassiveMountOnFiber(root, fiber, committedLanes);
} catch (error) {
reportUncaughtErrorInDEV(error);
captureCommitPhaseError(fiber, fiber.return, error);
Expand All @@ -2693,6 +2674,7 @@ function commitPassiveMountEffects_complete(
function commitPassiveMountOnFiber(
finishedRoot: FiberRoot,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
switch (finishedWork.tag) {
case FunctionComponent:
Expand Down Expand Up @@ -2734,6 +2716,27 @@ function commitPassiveMountOnFiber(
}
}
}

if (enableTransitionTracing) {
const transitions = finishedWork.memoizedState.transitions;
if (transitions !== null) {
transitions.forEach(transition => {
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
addTransitionStartCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});

addTransitionCompleteCallbackToPendingTransition({
transitionName: transition.name,
startTime: transition.startTime,
});
});

clearTransitionsForLanes(finishedRoot, committedLanes);
finishedWork.memoizedState.transitions = null;
}
}
break;
}
case LegacyHiddenComponent:
Expand Down
26 changes: 26 additions & 0 deletions packages/react-reconciler/src/ReactFiberCompleteWork.new.js
Expand Up @@ -153,6 +153,7 @@ import {
popRenderLanes,
getRenderTargetTime,
subtreeRenderLanes,
getWorkInProgressTransitions,
} from './ReactFiberWorkLoop.new';
import {
OffscreenLane,
Expand Down Expand Up @@ -862,6 +863,17 @@ function completeWork(
}
case HostRoot: {
const fiberRoot = (workInProgress.stateNode: FiberRoot);

if (enableTransitionTracing) {
const transitions = getWorkInProgressTransitions();
// We set the Passive flag here because if there are new transitions,
// we will need to schedule callbacks and process the transitions,
// which we do in the passive phase
if (transitions !== null) {
workInProgress.flags |= Passive;
}
}

if (enableCache) {
popRootTransition(fiberRoot, renderLanes);

Expand Down Expand Up @@ -918,6 +930,14 @@ function completeWork(
}
updateHostContainer(current, workInProgress);
bubbleProperties(workInProgress);
if (enableTransitionTracing) {
if ((workInProgress.subtreeFlags & Visibility) !== NoFlags) {
// If any of our suspense children toggle visibility, this means that
// the pending boundaries array needs to be updated, which we only
// do in the passive phase.
workInProgress.flags |= Passive;
}
}
return null;
}
case HostComponent: {
Expand Down Expand Up @@ -1187,6 +1207,12 @@ function completeWork(
const offscreenFiber: Fiber = (workInProgress.child: any);
offscreenFiber.flags |= Visibility;

// If the suspended state of the boundary changes, we need to schedule
// a passive effect, which is when we process the transitions
if (enableTransitionTracing) {
offscreenFiber.flags |= Passive;
}

// TODO: This will still suspend a synchronous tree if anything
// in the concurrent tree already suspended during this render.
// This is a known bug.
Expand Down
26 changes: 26 additions & 0 deletions packages/react-reconciler/src/ReactFiberCompleteWork.old.js
Expand Up @@ -153,6 +153,7 @@ import {
popRenderLanes,
getRenderTargetTime,
subtreeRenderLanes,
getWorkInProgressTransitions,
} from './ReactFiberWorkLoop.old';
import {
OffscreenLane,
Expand Down Expand Up @@ -862,6 +863,17 @@ function completeWork(
}
case HostRoot: {
const fiberRoot = (workInProgress.stateNode: FiberRoot);

if (enableTransitionTracing) {
const transitions = getWorkInProgressTransitions();
// We set the Passive flag here because if there are new transitions,
// we will need to schedule callbacks and process the transitions,
// which we do in the passive phase
if (transitions !== null) {
workInProgress.flags |= Passive;
}
}

if (enableCache) {
popRootTransition(fiberRoot, renderLanes);

Expand Down Expand Up @@ -918,6 +930,14 @@ function completeWork(
}
updateHostContainer(current, workInProgress);
bubbleProperties(workInProgress);
if (enableTransitionTracing) {
if ((workInProgress.subtreeFlags & Visibility) !== NoFlags) {
// If any of our suspense children toggle visibility, this means that
// the pending boundaries array needs to be updated, which we only
// do in the passive phase.
workInProgress.flags |= Passive;
}
}
return null;
}
case HostComponent: {
Expand Down Expand Up @@ -1187,6 +1207,12 @@ function completeWork(
const offscreenFiber: Fiber = (workInProgress.child: any);
offscreenFiber.flags |= Visibility;

// If the suspended state of the boundary changes, we need to schedule
// a passive effect, which is when we process the transitions
if (enableTransitionTracing) {
offscreenFiber.flags |= Passive;
}

// TODO: This will still suspend a synchronous tree if anything
// in the concurrent tree already suspended during this render.
// This is a known bug.
Expand Down

0 comments on commit 4ebaeae

Please sign in to comment.