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;