@samitouri / QOS-React-2 / commits / 741dcbdbec

Schedule passive phase whenever there's a deletion (#20624)

We use the passive phase to detach the fibers.

Andrew Clark committed Jan 20, 2021 at 12:21 UTC 741dcbdbec52b088e33538cd93c679c05c146aa1
4 files changed +11 -93
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+1 -27
@@ -136,8 +136,6 @@ import {
136 captureCommitPhaseError,
137 resolveRetryWakeable,
138 markCommitTimeOfFallback,
139 - enqueuePendingPassiveHookEffectMount,
140 - enqueuePendingPassiveHookEffectUnmount,
139 enqueuePendingPassiveProfilerEffect,
140 } from './ReactFiberWorkLoop.new';
141 import {
@@ -533,26 +531,6 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
531 }
532 }
533
536 -function schedulePassiveEffects(finishedWork: Fiber) {
537 - const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
538 - const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
539 - if (lastEffect !== null) {
540 - const firstEffect = lastEffect.next;
541 - let effect = firstEffect;
542 - do {
543 - const {next, tag} = effect;
544 - if (
545 - (tag & HookPassive) !== NoHookEffect &&
546 - (tag & HookHasEffect) !== NoHookEffect
547 - ) {
548 - enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);
549 - enqueuePendingPassiveHookEffectMount(finishedWork, effect);
550 - }
551 - effect = next;
552 - } while (effect !== firstEffect);
553 - }
554 -}
555 -
534 export function commitPassiveEffectDurations(
535 finishedRoot: FiberRoot,
536 finishedWork: Fiber,
@@ -639,8 +617,6 @@ function commitLayoutEffectOnFiber(
617 } else {
618 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
619 }
642 -
643 - schedulePassiveEffects(finishedWork);
620 break;
621 }
622 case ClassComponent: {
@@ -1091,9 +1067,7 @@ function commitUnmount(
1067 do {
1068 const {destroy, tag} = effect;
1069 if (destroy !== undefined) {
1094 - if ((tag & HookPassive) !== NoHookEffect) {
1095 - enqueuePendingPassiveHookEffectUnmount(current, effect);
1096 - } else {
1070 + if ((tag & HookLayout) !== NoHookEffect) {
1071 if (
1072 enableProfilerTimer &&
1073 enableProfilerCommitHooks &&
packages/react-reconciler/src/ReactFiberFlags.js
+2
@@ -81,6 +81,8 @@ export const MutationMask =
81 Hydrating |
82 Visibility;
83 export const LayoutMask = Update | Callback | Ref;
84 +
85 +// TODO: Split into PassiveMountMask and PassiveUnmountMask
86 export const PassiveMask = Passive | ChildDeletion;
87
88 // Union of tags that don't get reset on clones.
packages/react-reconciler/src/ReactFiberHooks.new.js
+5 -8
@@ -472,6 +472,8 @@ export function bailoutHooks(
472 lanes: Lanes,
473 ) {
474 workInProgress.updateQueue = current.updateQueue;
475 + // TODO: Don't need to reset the flags here, because they're reset in the
476 + // complete phase (bubbleProperties).
477 workInProgress.flags &= ~(PassiveEffect | UpdateEffect);
478 current.lanes = removeLanes(current.lanes, lanes);
479 }
@@ -1309,7 +1311,7 @@ function mountEffect(
1311 }
1312 }
1313 return mountEffectImpl(
1312 - UpdateEffect | PassiveEffect | PassiveStaticEffect,
1314 + PassiveEffect | PassiveStaticEffect,
1315 HookPassive,
1316 create,
1317 deps,
@@ -1326,12 +1328,7 @@ function updateEffect(
1328 warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber);
1329 }
1330 }
1329 - return updateEffectImpl(
1330 - UpdateEffect | PassiveEffect,
1331 - HookPassive,
1332 - create,
1333 - deps,
1334 - );
1331 + return updateEffectImpl(PassiveEffect, HookPassive, create, deps);
1332 }
1333
1334 function mountLayoutEffect(
@@ -1683,7 +1680,7 @@ function mountOpaqueIdentifier(): OpaqueIDType | void {
1680 const setId = mountState(id)[1];
1681
1682 if ((currentlyRenderingFiber.mode & BlockingMode) === NoMode) {
1686 - currentlyRenderingFiber.flags |= UpdateEffect | PassiveEffect;
1683 + currentlyRenderingFiber.flags |= PassiveEffect;
1684 pushEffect(
1685 HookHasEffect | HookPassive,
1686 () => {
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+3 -58
@@ -13,7 +13,6 @@ import type {Lanes, Lane} from './ReactFiberLane.new';
13 import type {ReactPriorityLevel} from './ReactInternalTypes';
14 import type {Interaction} from 'scheduler/src/Tracing';
15 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
16 -import type {Effect as HookEffect} from './ReactFiberHooks.new';
16 import type {StackCursor} from './ReactFiberStack.new';
17 import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.new';
18
@@ -120,12 +119,11 @@ import {
119 NoFlags,
120 PerformedWork,
121 Placement,
123 - ChildDeletion,
124 - Passive,
122 PassiveStatic,
123 Incomplete,
124 HostEffectMask,
125 Hydrating,
126 + PassiveMask,
127 StaticMask,
128 } from './ReactFiberFlags';
129 import {
@@ -183,7 +181,6 @@ import {
181 commitPassiveEffectDurations,
182 commitPassiveMountEffects,
183 commitPassiveUnmountEffects,
186 - detachFiberAfterEffects,
184 } from './ReactFiberCommitWork.new';
185 import {enqueueUpdate} from './ReactUpdateQueue.new';
186 import {resetContextDependencies} from './ReactFiberNewContext.new';
@@ -314,7 +311,6 @@ export function getRenderTargetTime(): number {
311 return workInProgressRootRenderTargetTime;
312 }
313
317 -let nextEffect: Fiber | null = null;
314 let hasUncaughtError = false;
315 let firstUncaughtError = null;
316 let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;
@@ -1938,8 +1934,8 @@ function commitRootImpl(root, renderPriorityLevel) {
1934 // TODO: Delete all other places that schedule the passive effect callback
1935 // They're redundant.
1936 if (
1941 - (finishedWork.subtreeFlags & Passive) !== NoFlags ||
1942 - (finishedWork.flags & Passive) !== NoFlags
1937 + (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||
1938 + (finishedWork.flags & PassiveMask) !== NoFlags
1939 ) {
1940 if (!rootDoesHavePassiveEffects) {
1941 rootDoesHavePassiveEffects = true;
@@ -2061,31 +2057,6 @@ function commitRootImpl(root, renderPriorityLevel) {
2057 rootWithPendingPassiveEffects = root;
2058 pendingPassiveEffectsLanes = lanes;
2059 pendingPassiveEffectsRenderPriority = renderPriorityLevel;
2064 - } else {
2065 - // We are done with the effect chain at this point so let's clear the
2066 - // nextEffect pointers to assist with GC. If we have passive effects, we'll
2067 - // clear this in flushPassiveEffects
2068 - // TODO: We should always do this in the passive phase, by scheduling
2069 - // a passive callback for every deletion.
2070 - nextEffect = firstEffect;
2071 - while (nextEffect !== null) {
2072 - const nextNextEffect = nextEffect.nextEffect;
2073 - nextEffect.nextEffect = null;
2074 - if (nextEffect.flags & ChildDeletion) {
2075 - const deletions = nextEffect.deletions;
2076 - if (deletions !== null) {
2077 - for (let i = 0; i < deletions.length; i++) {
2078 - const deletion = deletions[i];
2079 - const alternate = deletion.alternate;
2080 - detachFiberAfterEffects(deletion);
2081 - if (alternate !== null) {
2082 - detachFiberAfterEffects(alternate);
2083 - }
2084 - }
2085 - }
2086 - }
2087 - nextEffect = nextNextEffect;
2088 - }
2060 }
2061
2062 // Read this again, since an effect might have updated it
@@ -2229,32 +2200,6 @@ export function enqueuePendingPassiveProfilerEffect(fiber: Fiber): void {
2200 }
2201 }
2202
2232 -export function enqueuePendingPassiveHookEffectMount(
2233 - fiber: Fiber,
2234 - effect: HookEffect,
2235 -): void {
2236 - if (!rootDoesHavePassiveEffects) {
2237 - rootDoesHavePassiveEffects = true;
2238 - scheduleCallback(NormalSchedulerPriority, () => {
2239 - flushPassiveEffects();
2240 - return null;
2241 - });
2242 - }
2243 -}
2244 -
2245 -export function enqueuePendingPassiveHookEffectUnmount(
2246 - fiber: Fiber,
2247 - effect: HookEffect,
2248 -): void {
2249 - if (!rootDoesHavePassiveEffects) {
2250 - rootDoesHavePassiveEffects = true;
2251 - scheduleCallback(NormalSchedulerPriority, () => {
2252 - flushPassiveEffects();
2253 - return null;
2254 - });
2255 - }
2256 -}
2257 -
2203 function flushPassiveEffectsImpl() {
2204 if (rootWithPendingPassiveEffects === null) {
2205 return false;