Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4ebaeae

Browse files
authoredApr 8, 2022
moved mutation code to passive (#24251)
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?
1 parent 5b2e725 commit 4ebaeae

File tree

6 files changed

+176
-104
lines changed

6 files changed

+176
-104
lines changed
 

‎packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,32 +2227,6 @@ function commitMutationEffectsOnFiber(
22272227
// because of the shared reconciliation logic below.
22282228
const flags = finishedWork.flags;
22292229

2230-
if (enableTransitionTracing) {
2231-
switch (finishedWork.tag) {
2232-
case HostRoot: {
2233-
const state = finishedWork.memoizedState;
2234-
const transitions = state.transitions;
2235-
if (transitions !== null) {
2236-
transitions.forEach(transition => {
2237-
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
2238-
addTransitionStartCallbackToPendingTransition({
2239-
transitionName: transition.name,
2240-
startTime: transition.startTime,
2241-
});
2242-
2243-
addTransitionCompleteCallbackToPendingTransition({
2244-
transitionName: transition.name,
2245-
startTime: transition.startTime,
2246-
});
2247-
});
2248-
2249-
clearTransitionsForLanes(root, lanes);
2250-
state.transitions = null;
2251-
}
2252-
}
2253-
}
2254-
}
2255-
22562230
if (flags & ContentReset) {
22572231
commitResetTextContent(finishedWork);
22582232
}
@@ -2639,34 +2613,41 @@ function reappearLayoutEffects_complete(subtreeRoot: Fiber) {
26392613
export function commitPassiveMountEffects(
26402614
root: FiberRoot,
26412615
finishedWork: Fiber,
2616+
committedLanes: Lanes,
26422617
): void {
26432618
nextEffect = finishedWork;
2644-
commitPassiveMountEffects_begin(finishedWork, root);
2619+
commitPassiveMountEffects_begin(finishedWork, root, committedLanes);
26452620
}
26462621

2647-
function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
2622+
function commitPassiveMountEffects_begin(
2623+
subtreeRoot: Fiber,
2624+
root: FiberRoot,
2625+
committedLanes: Lanes,
2626+
) {
26482627
while (nextEffect !== null) {
26492628
const fiber = nextEffect;
26502629
const firstChild = fiber.child;
26512630
if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {
26522631
ensureCorrectReturnPointer(firstChild, fiber);
26532632
nextEffect = firstChild;
26542633
} else {
2655-
commitPassiveMountEffects_complete(subtreeRoot, root);
2634+
commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes);
26562635
}
26572636
}
26582637
}
26592638

26602639
function commitPassiveMountEffects_complete(
26612640
subtreeRoot: Fiber,
26622641
root: FiberRoot,
2642+
committedLanes: Lanes,
26632643
) {
26642644
while (nextEffect !== null) {
26652645
const fiber = nextEffect;
2646+
26662647
if ((fiber.flags & Passive) !== NoFlags) {
26672648
setCurrentDebugFiberInDEV(fiber);
26682649
try {
2669-
commitPassiveMountOnFiber(root, fiber);
2650+
commitPassiveMountOnFiber(root, fiber, committedLanes);
26702651
} catch (error) {
26712652
reportUncaughtErrorInDEV(error);
26722653
captureCommitPhaseError(fiber, fiber.return, error);
@@ -2693,6 +2674,7 @@ function commitPassiveMountEffects_complete(
26932674
function commitPassiveMountOnFiber(
26942675
finishedRoot: FiberRoot,
26952676
finishedWork: Fiber,
2677+
committedLanes: Lanes,
26962678
): void {
26972679
switch (finishedWork.tag) {
26982680
case FunctionComponent:
@@ -2734,6 +2716,27 @@ function commitPassiveMountOnFiber(
27342716
}
27352717
}
27362718
}
2719+
2720+
if (enableTransitionTracing) {
2721+
const transitions = finishedWork.memoizedState.transitions;
2722+
if (transitions !== null) {
2723+
transitions.forEach(transition => {
2724+
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
2725+
addTransitionStartCallbackToPendingTransition({
2726+
transitionName: transition.name,
2727+
startTime: transition.startTime,
2728+
});
2729+
2730+
addTransitionCompleteCallbackToPendingTransition({
2731+
transitionName: transition.name,
2732+
startTime: transition.startTime,
2733+
});
2734+
});
2735+
2736+
clearTransitionsForLanes(finishedRoot, committedLanes);
2737+
finishedWork.memoizedState.transitions = null;
2738+
}
2739+
}
27372740
break;
27382741
}
27392742
case LegacyHiddenComponent:

‎packages/react-reconciler/src/ReactFiberCommitWork.old.js

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,32 +2227,6 @@ function commitMutationEffectsOnFiber(
22272227
// because of the shared reconciliation logic below.
22282228
const flags = finishedWork.flags;
22292229

2230-
if (enableTransitionTracing) {
2231-
switch (finishedWork.tag) {
2232-
case HostRoot: {
2233-
const state = finishedWork.memoizedState;
2234-
const transitions = state.transitions;
2235-
if (transitions !== null) {
2236-
transitions.forEach(transition => {
2237-
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
2238-
addTransitionStartCallbackToPendingTransition({
2239-
transitionName: transition.name,
2240-
startTime: transition.startTime,
2241-
});
2242-
2243-
addTransitionCompleteCallbackToPendingTransition({
2244-
transitionName: transition.name,
2245-
startTime: transition.startTime,
2246-
});
2247-
});
2248-
2249-
clearTransitionsForLanes(root, lanes);
2250-
state.transitions = null;
2251-
}
2252-
}
2253-
}
2254-
}
2255-
22562230
if (flags & ContentReset) {
22572231
commitResetTextContent(finishedWork);
22582232
}
@@ -2639,34 +2613,41 @@ function reappearLayoutEffects_complete(subtreeRoot: Fiber) {
26392613
export function commitPassiveMountEffects(
26402614
root: FiberRoot,
26412615
finishedWork: Fiber,
2616+
committedLanes: Lanes,
26422617
): void {
26432618
nextEffect = finishedWork;
2644-
commitPassiveMountEffects_begin(finishedWork, root);
2619+
commitPassiveMountEffects_begin(finishedWork, root, committedLanes);
26452620
}
26462621

2647-
function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
2622+
function commitPassiveMountEffects_begin(
2623+
subtreeRoot: Fiber,
2624+
root: FiberRoot,
2625+
committedLanes: Lanes,
2626+
) {
26482627
while (nextEffect !== null) {
26492628
const fiber = nextEffect;
26502629
const firstChild = fiber.child;
26512630
if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {
26522631
ensureCorrectReturnPointer(firstChild, fiber);
26532632
nextEffect = firstChild;
26542633
} else {
2655-
commitPassiveMountEffects_complete(subtreeRoot, root);
2634+
commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes);
26562635
}
26572636
}
26582637
}
26592638

26602639
function commitPassiveMountEffects_complete(
26612640
subtreeRoot: Fiber,
26622641
root: FiberRoot,
2642+
committedLanes: Lanes,
26632643
) {
26642644
while (nextEffect !== null) {
26652645
const fiber = nextEffect;
2646+
26662647
if ((fiber.flags & Passive) !== NoFlags) {
26672648
setCurrentDebugFiberInDEV(fiber);
26682649
try {
2669-
commitPassiveMountOnFiber(root, fiber);
2650+
commitPassiveMountOnFiber(root, fiber, committedLanes);
26702651
} catch (error) {
26712652
reportUncaughtErrorInDEV(error);
26722653
captureCommitPhaseError(fiber, fiber.return, error);
@@ -2693,6 +2674,7 @@ function commitPassiveMountEffects_complete(
26932674
function commitPassiveMountOnFiber(
26942675
finishedRoot: FiberRoot,
26952676
finishedWork: Fiber,
2677+
committedLanes: Lanes,
26962678
): void {
26972679
switch (finishedWork.tag) {
26982680
case FunctionComponent:
@@ -2734,6 +2716,27 @@ function commitPassiveMountOnFiber(
27342716
}
27352717
}
27362718
}
2719+
2720+
if (enableTransitionTracing) {
2721+
const transitions = finishedWork.memoizedState.transitions;
2722+
if (transitions !== null) {
2723+
transitions.forEach(transition => {
2724+
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
2725+
addTransitionStartCallbackToPendingTransition({
2726+
transitionName: transition.name,
2727+
startTime: transition.startTime,
2728+
});
2729+
2730+
addTransitionCompleteCallbackToPendingTransition({
2731+
transitionName: transition.name,
2732+
startTime: transition.startTime,
2733+
});
2734+
});
2735+
2736+
clearTransitionsForLanes(finishedRoot, committedLanes);
2737+
finishedWork.memoizedState.transitions = null;
2738+
}
2739+
}
27372740
break;
27382741
}
27392742
case LegacyHiddenComponent:

‎packages/react-reconciler/src/ReactFiberCompleteWork.new.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ import {
153153
popRenderLanes,
154154
getRenderTargetTime,
155155
subtreeRenderLanes,
156+
getWorkInProgressTransitions,
156157
} from './ReactFiberWorkLoop.new';
157158
import {
158159
OffscreenLane,
@@ -862,6 +863,17 @@ function completeWork(
862863
}
863864
case HostRoot: {
864865
const fiberRoot = (workInProgress.stateNode: FiberRoot);
866+
867+
if (enableTransitionTracing) {
868+
const transitions = getWorkInProgressTransitions();
869+
// We set the Passive flag here because if there are new transitions,
870+
// we will need to schedule callbacks and process the transitions,
871+
// which we do in the passive phase
872+
if (transitions !== null) {
873+
workInProgress.flags |= Passive;
874+
}
875+
}
876+
865877
if (enableCache) {
866878
popRootTransition(fiberRoot, renderLanes);
867879

@@ -918,6 +930,14 @@ function completeWork(
918930
}
919931
updateHostContainer(current, workInProgress);
920932
bubbleProperties(workInProgress);
933+
if (enableTransitionTracing) {
934+
if ((workInProgress.subtreeFlags & Visibility) !== NoFlags) {
935+
// If any of our suspense children toggle visibility, this means that
936+
// the pending boundaries array needs to be updated, which we only
937+
// do in the passive phase.
938+
workInProgress.flags |= Passive;
939+
}
940+
}
921941
return null;
922942
}
923943
case HostComponent: {
@@ -1187,6 +1207,12 @@ function completeWork(
11871207
const offscreenFiber: Fiber = (workInProgress.child: any);
11881208
offscreenFiber.flags |= Visibility;
11891209

1210+
// If the suspended state of the boundary changes, we need to schedule
1211+
// a passive effect, which is when we process the transitions
1212+
if (enableTransitionTracing) {
1213+
offscreenFiber.flags |= Passive;
1214+
}
1215+
11901216
// TODO: This will still suspend a synchronous tree if anything
11911217
// in the concurrent tree already suspended during this render.
11921218
// This is a known bug.

‎packages/react-reconciler/src/ReactFiberCompleteWork.old.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ import {
153153
popRenderLanes,
154154
getRenderTargetTime,
155155
subtreeRenderLanes,
156+
getWorkInProgressTransitions,
156157
} from './ReactFiberWorkLoop.old';
157158
import {
158159
OffscreenLane,
@@ -862,6 +863,17 @@ function completeWork(
862863
}
863864
case HostRoot: {
864865
const fiberRoot = (workInProgress.stateNode: FiberRoot);
866+
867+
if (enableTransitionTracing) {
868+
const transitions = getWorkInProgressTransitions();
869+
// We set the Passive flag here because if there are new transitions,
870+
// we will need to schedule callbacks and process the transitions,
871+
// which we do in the passive phase
872+
if (transitions !== null) {
873+
workInProgress.flags |= Passive;
874+
}
875+
}
876+
865877
if (enableCache) {
866878
popRootTransition(fiberRoot, renderLanes);
867879

@@ -918,6 +930,14 @@ function completeWork(
918930
}
919931
updateHostContainer(current, workInProgress);
920932
bubbleProperties(workInProgress);
933+
if (enableTransitionTracing) {
934+
if ((workInProgress.subtreeFlags & Visibility) !== NoFlags) {
935+
// If any of our suspense children toggle visibility, this means that
936+
// the pending boundaries array needs to be updated, which we only
937+
// do in the passive phase.
938+
workInProgress.flags |= Passive;
939+
}
940+
}
921941
return null;
922942
}
923943
case HostComponent: {
@@ -1187,6 +1207,12 @@ function completeWork(
11871207
const offscreenFiber: Fiber = (workInProgress.child: any);
11881208
offscreenFiber.flags |= Visibility;
11891209

1210+
// If the suspended state of the boundary changes, we need to schedule
1211+
// a passive effect, which is when we process the transitions
1212+
if (enableTransitionTracing) {
1213+
offscreenFiber.flags |= Passive;
1214+
}
1215+
11901216
// TODO: This will still suspend a synchronous tree if anything
11911217
// in the concurrent tree already suspended during this render.
11921218
// This is a known bug.

‎packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,27 +2322,6 @@ function commitRootImpl(
23222322
// If layout work was scheduled, flush it now.
23232323
flushSyncCallbacks();
23242324

2325-
if (enableTransitionTracing) {
2326-
const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
2327-
const prevRootTransitionCallbacks = root.transitionCallbacks;
2328-
if (
2329-
prevPendingTransitionCallbacks !== null &&
2330-
prevRootTransitionCallbacks !== null
2331-
) {
2332-
// TODO(luna) Refactor this code into the Host Config
2333-
const endTime = now();
2334-
currentPendingTransitionCallbacks = null;
2335-
2336-
scheduleCallback(IdleSchedulerPriority, () =>
2337-
processTransitionCallbacks(
2338-
prevPendingTransitionCallbacks,
2339-
endTime,
2340-
prevRootTransitionCallbacks,
2341-
),
2342-
);
2343-
}
2344-
}
2345-
23462325
if (__DEV__) {
23472326
if (enableDebugTracing) {
23482327
logCommitStopped();
@@ -2457,7 +2436,7 @@ function flushPassiveEffectsImpl() {
24572436
executionContext |= CommitContext;
24582437

24592438
commitPassiveUnmountEffects(root.current);
2460-
commitPassiveMountEffects(root, root.current);
2439+
commitPassiveMountEffects(root, root.current, lanes);
24612440

24622441
// TODO: Move to commitPassiveMountEffects
24632442
if (enableProfilerTimer && enableProfilerCommitHooks) {
@@ -2487,6 +2466,34 @@ function flushPassiveEffectsImpl() {
24872466

24882467
flushSyncCallbacks();
24892468

2469+
if (enableTransitionTracing) {
2470+
const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
2471+
const prevRootTransitionCallbacks = root.transitionCallbacks;
2472+
if (
2473+
prevPendingTransitionCallbacks !== null &&
2474+
prevRootTransitionCallbacks !== null
2475+
) {
2476+
// TODO(luna) Refactor this code into the Host Config
2477+
// TODO(luna) The end time here is not necessarily accurate
2478+
// because passive effects could be called before paint
2479+
// (synchronously) or after paint (normally). We need
2480+
// to come up with a way to get the correct end time for both cases.
2481+
// One solution is in the host config, if the passive effects
2482+
// have not yet been run, make a call to flush the passive effects
2483+
// right after paint.
2484+
const endTime = now();
2485+
currentPendingTransitionCallbacks = null;
2486+
2487+
scheduleCallback(IdleSchedulerPriority, () =>
2488+
processTransitionCallbacks(
2489+
prevPendingTransitionCallbacks,
2490+
endTime,
2491+
prevRootTransitionCallbacks,
2492+
),
2493+
);
2494+
}
2495+
}
2496+
24902497
if (__DEV__) {
24912498
// If additional passive effects were scheduled, increment a counter. If this
24922499
// exceeds the limit, we'll fire a warning.

‎packages/react-reconciler/src/ReactFiberWorkLoop.old.js

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,27 +2322,6 @@ function commitRootImpl(
23222322
// If layout work was scheduled, flush it now.
23232323
flushSyncCallbacks();
23242324

2325-
if (enableTransitionTracing) {
2326-
const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
2327-
const prevRootTransitionCallbacks = root.transitionCallbacks;
2328-
if (
2329-
prevPendingTransitionCallbacks !== null &&
2330-
prevRootTransitionCallbacks !== null
2331-
) {
2332-
// TODO(luna) Refactor this code into the Host Config
2333-
const endTime = now();
2334-
currentPendingTransitionCallbacks = null;
2335-
2336-
scheduleCallback(IdleSchedulerPriority, () =>
2337-
processTransitionCallbacks(
2338-
prevPendingTransitionCallbacks,
2339-
endTime,
2340-
prevRootTransitionCallbacks,
2341-
),
2342-
);
2343-
}
2344-
}
2345-
23462325
if (__DEV__) {
23472326
if (enableDebugTracing) {
23482327
logCommitStopped();
@@ -2457,7 +2436,7 @@ function flushPassiveEffectsImpl() {
24572436
executionContext |= CommitContext;
24582437

24592438
commitPassiveUnmountEffects(root.current);
2460-
commitPassiveMountEffects(root, root.current);
2439+
commitPassiveMountEffects(root, root.current, lanes);
24612440

24622441
// TODO: Move to commitPassiveMountEffects
24632442
if (enableProfilerTimer && enableProfilerCommitHooks) {
@@ -2487,6 +2466,34 @@ function flushPassiveEffectsImpl() {
24872466

24882467
flushSyncCallbacks();
24892468

2469+
if (enableTransitionTracing) {
2470+
const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
2471+
const prevRootTransitionCallbacks = root.transitionCallbacks;
2472+
if (
2473+
prevPendingTransitionCallbacks !== null &&
2474+
prevRootTransitionCallbacks !== null
2475+
) {
2476+
// TODO(luna) Refactor this code into the Host Config
2477+
// TODO(luna) The end time here is not necessarily accurate
2478+
// because passive effects could be called before paint
2479+
// (synchronously) or after paint (normally). We need
2480+
// to come up with a way to get the correct end time for both cases.
2481+
// One solution is in the host config, if the passive effects
2482+
// have not yet been run, make a call to flush the passive effects
2483+
// right after paint.
2484+
const endTime = now();
2485+
currentPendingTransitionCallbacks = null;
2486+
2487+
scheduleCallback(IdleSchedulerPriority, () =>
2488+
processTransitionCallbacks(
2489+
prevPendingTransitionCallbacks,
2490+
endTime,
2491+
prevRootTransitionCallbacks,
2492+
),
2493+
);
2494+
}
2495+
}
2496+
24902497
if (__DEV__) {
24912498
// If additional passive effects were scheduled, increment a counter. If this
24922499
// exceeds the limit, we'll fire a warning.

0 commit comments

Comments
 (0)
Please sign in to comment.