Combine Flags and SubtreeFlags types (#19775)
Because the `subtreeFlags` is the union of all the flags present in a subtree, we can use the same type as `flags`. One practical benefit is that we can bubble up the flags from the children with a single `|=` operator. Structurally, everything else about the effect algorithm is unchanged.
Andrew Clark committed
Sep 4, 2020 at 16:48 UTC
7baf9d4128d41903de125527b50285ea9862cf9a
6 files changed
+38
-113
packages/react-reconciler/src/ReactFiber.new.js
+3
-4
@@ -30,7 +30,6 @@ import {
30
enableBlocksAPI,
31
} from 'shared/ReactFeatureFlags';
32
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
33
-import {NoFlags as NoSubtreeEffect} from './ReactSubtreeFlags';
33
import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
34
import {
35
IndeterminateComponent,
@@ -145,7 +144,7 @@ function FiberNode(
144
145
// Effects
146
this.flags = NoFlags;
148
- this.subtreeFlags = NoSubtreeEffect;
147
+ this.subtreeFlags = NoFlags;
148
this.deletions = null;
149
150
this.lanes = NoLanes;
@@ -284,7 +283,7 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
283
workInProgress.type = current.type;
284
285
// We already have an alternate.
287
- workInProgress.subtreeFlags = NoSubtreeEffect;
286
+ workInProgress.subtreeFlags = NoFlags;
287
workInProgress.deletions = null;
288
289
if (enableProfilerTimer) {
@@ -372,7 +371,7 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
371
workInProgress.lanes = renderLanes;
372
373
workInProgress.child = null;
375
- workInProgress.subtreeFlags = NoSubtreeEffect;
374
+ workInProgress.subtreeFlags = NoFlags;
375
workInProgress.memoizedProps = null;
376
workInProgress.memoizedState = null;
377
workInProgress.updateQueue = null;
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+2
-8
@@ -71,6 +71,7 @@ import {
71
Placement,
72
Snapshot,
73
Update,
74
+ PassiveMask,
75
} from './ReactFiberFlags';
76
import getComponentName from 'shared/getComponentName';
77
import invariant from 'shared/invariant';
@@ -130,10 +131,6 @@ import {
131
Passive as HookPassive,
132
} from './ReactHookEffectTags';
133
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';
133
-import {
134
- NoFlags as NoSubtreeFlags,
135
- Passive as PassiveSubtreeFlags,
136
-} from './ReactSubtreeFlags';
134
135
let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
136
if (__DEV__) {
@@ -595,10 +592,7 @@ function commitLifeCycles(
592
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
593
}
594
598
- if (
599
- (finishedWork.subtreeFlags & PassiveSubtreeFlags) !==
600
- NoSubtreeFlags
601
- ) {
595
+ if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) {
596
schedulePassiveEffectCallback();
597
}
598
return;
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+1
-2
@@ -67,7 +67,6 @@ import {
67
Snapshot,
68
MutationMask,
69
} from './ReactFiberFlags';
70
-import {NoFlags as NoSubtreeFlags, Mutation} from './ReactSubtreeFlags';
70
import invariant from 'shared/invariant';
71
72
import {
@@ -166,7 +165,7 @@ function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {
165
if ((child.flags & MutationMask) !== NoFlags) {
166
return false;
167
}
169
- if ((child.subtreeFlags & Mutation) !== NoSubtreeFlags) {
168
+ if ((child.subtreeFlags & MutationMask) !== NoFlags) {
169
return false;
170
}
171
child = child.sibling;
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+31
-79
@@ -139,15 +139,8 @@ import {
139
MutationMask,
140
LayoutMask,
141
PassiveMask,
142
+ StaticMask,
143
} from './ReactFiberFlags';
143
-import {
144
- NoFlags as NoSubtreeFlags,
145
- BeforeMutation as BeforeMutationSubtreeFlags,
146
- Mutation as MutationSubtreeFlags,
147
- Layout as LayoutSubtreeFlags,
148
- Passive as PassiveSubtreeFlags,
149
- PassiveStatic as PassiveStaticSubtreeFlags,
150
-} from './ReactSubtreeFlags';
144
import {
145
NoLanePriority,
146
SyncLanePriority,
@@ -1766,7 +1759,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
1759
if (returnFiber !== null) {
1760
// Mark the parent fiber as incomplete
1761
returnFiber.flags |= Incomplete;
1769
- returnFiber.subtreeFlags = NoSubtreeFlags;
1762
+ returnFiber.subtreeFlags = NoFlags;
1763
returnFiber.deletions = null;
1764
}
1765
}
@@ -1809,7 +1802,7 @@ function resetChildLanes(completedWork: Fiber) {
1802
completedWork.alternate.child === completedWork.child;
1803
1804
let newChildLanes = NoLanes;
1812
- let subtreeFlags = NoSubtreeFlags;
1805
+ let subtreeFlags = NoFlags;
1806
1807
if (!didBailout) {
1808
// Bubble up the earliest expiration time.
@@ -1827,23 +1820,7 @@ function resetChildLanes(completedWork: Fiber) {
1820
);
1821
1822
subtreeFlags |= child.subtreeFlags;
1830
-
1831
- const flags = child.flags;
1832
- if ((flags & BeforeMutationMask) !== NoFlags) {
1833
- subtreeFlags |= BeforeMutationSubtreeFlags;
1834
- }
1835
- if ((flags & MutationMask) !== NoFlags) {
1836
- subtreeFlags |= MutationSubtreeFlags;
1837
- }
1838
- if ((flags & LayoutMask) !== NoFlags) {
1839
- subtreeFlags |= LayoutSubtreeFlags;
1840
- }
1841
- if ((flags & PassiveMask) !== NoFlags) {
1842
- subtreeFlags |= PassiveSubtreeFlags;
1843
- }
1844
- if ((flags & PassiveStatic) !== NoFlags) {
1845
- subtreeFlags |= PassiveStaticSubtreeFlags;
1846
- }
1823
+ subtreeFlags |= child.flags;
1824
1825
// When a fiber is cloned, its actualDuration is reset to 0. This value will
1826
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
@@ -1880,23 +1857,7 @@ function resetChildLanes(completedWork: Fiber) {
1857
);
1858
1859
subtreeFlags |= child.subtreeFlags;
1883
-
1884
- const flags = child.flags;
1885
- if ((flags & BeforeMutationMask) !== NoFlags) {
1886
- subtreeFlags |= BeforeMutationSubtreeFlags;
1887
- }
1888
- if ((flags & MutationMask) !== NoFlags) {
1889
- subtreeFlags |= MutationSubtreeFlags;
1890
- }
1891
- if ((flags & LayoutMask) !== NoFlags) {
1892
- subtreeFlags |= LayoutSubtreeFlags;
1893
- }
1894
- if ((flags & PassiveMask) !== NoFlags) {
1895
- subtreeFlags |= PassiveSubtreeFlags;
1896
- }
1897
- if ((flags & PassiveStatic) !== NoFlags) {
1898
- subtreeFlags |= PassiveStaticSubtreeFlags;
1899
- }
1860
+ subtreeFlags |= child.flags;
1861
1862
child = child.sibling;
1863
}
@@ -1917,13 +1878,12 @@ function resetChildLanes(completedWork: Fiber) {
1878
mergeLanes(child.lanes, child.childLanes),
1879
);
1880
1920
- // Preserve passive static flag even in the case of a bailout;
1921
- // otherwise a subsequent unmount may bailout before calling destroy functions.
1922
- subtreeFlags |= child.subtreeFlags & PassiveStaticSubtreeFlags;
1923
- const flags = child.flags;
1924
- if ((flags & PassiveStatic) !== NoFlags) {
1925
- subtreeFlags |= PassiveStaticSubtreeFlags;
1926
- }
1881
+ // "Static" flags share the lifetime of the fiber/hook they belong to,
1882
+ // so we should bubble those up even during a bailout. All the other
1883
+ // flags have a lifetime only of a single render + commit, so we should
1884
+ // ignore them.
1885
+ subtreeFlags |= child.subtreeFlags & StaticMask;
1886
+ subtreeFlags |= child.flags & StaticMask;
1887
1888
treeBaseDuration += child.treeBaseDuration;
1889
child = child.sibling;
@@ -1949,13 +1909,12 @@ function resetChildLanes(completedWork: Fiber) {
1909
mergeLanes(child.lanes, child.childLanes),
1910
);
1911
1952
- // Preserve passive static flag even in the case of a bailout;
1953
- // otherwise a subsequent unmount may bailout before calling destroy functions.
1954
- subtreeFlags |= child.subtreeFlags & PassiveStaticSubtreeFlags;
1955
- const flags = child.flags;
1956
- if ((flags & PassiveStatic) !== NoFlags) {
1957
- subtreeFlags |= PassiveStaticSubtreeFlags;
1958
- }
1912
+ // "Static" flags share the lifetime of the fiber/hook they belong to,
1913
+ // so we should bubble those up even during a bailout. All the other
1914
+ // flags have a lifetime only of a single render + commit, so we should
1915
+ // ignore them.
1916
+ subtreeFlags |= child.subtreeFlags & StaticMask;
1917
+ subtreeFlags |= child.flags & StaticMask;
1918
1919
child = child.sibling;
1920
}
@@ -2067,11 +2026,8 @@ function commitRootImpl(root, renderPriorityLevel) {
2026
// Reconsider whether this is necessary.
2027
const subtreeHasEffects =
2028
(finishedWork.subtreeFlags &
2070
- (BeforeMutationSubtreeFlags |
2071
- MutationSubtreeFlags |
2072
- LayoutSubtreeFlags |
2073
- PassiveSubtreeFlags)) !==
2074
- NoSubtreeFlags;
2029
+ (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
2030
+ NoFlags;
2031
const rootHasEffect =
2032
(finishedWork.flags &
2033
(BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
@@ -2152,7 +2108,7 @@ function commitRootImpl(root, renderPriorityLevel) {
2108
2109
// If there are pending passive effects, schedule a callback to process them.
2110
if (
2155
- (finishedWork.subtreeFlags & PassiveSubtreeFlags) !== NoSubtreeFlags ||
2111
+ (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||
2112
(finishedWork.flags & PassiveMask) !== NoFlags
2113
) {
2114
if (!rootDoesHavePassiveEffects) {
@@ -2306,9 +2262,8 @@ function commitBeforeMutationEffects(firstChild: Fiber) {
2262
}
2263
2264
if (fiber.child !== null) {
2309
- const primarySubtreeFlags =
2310
- fiber.subtreeFlags & BeforeMutationSubtreeFlags;
2311
- if (primarySubtreeFlags !== NoSubtreeFlags) {
2265
+ const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;
2266
+ if (primarySubtreeFlags !== NoFlags) {
2267
commitBeforeMutationEffects(fiber.child);
2268
}
2269
}
@@ -2402,8 +2357,8 @@ function commitMutationEffects(
2357
}
2358
2359
if (fiber.child !== null) {
2405
- const primarySubtreeFlags = fiber.subtreeFlags & MutationSubtreeFlags;
2406
- if (primarySubtreeFlags !== NoSubtreeFlags) {
2360
+ const mutationFlags = fiber.subtreeFlags & MutationMask;
2361
+ if (mutationFlags !== NoFlags) {
2362
commitMutationEffects(fiber.child, root, renderPriorityLevel);
2363
}
2364
}
@@ -2560,8 +2515,8 @@ function commitLayoutEffects(
2515
let fiber = firstChild;
2516
while (fiber !== null) {
2517
if (fiber.child !== null) {
2563
- const primarySubtreeFlags = fiber.subtreeFlags & LayoutSubtreeFlags;
2564
- if (primarySubtreeFlags !== NoSubtreeFlags) {
2518
+ const primarySubtreeFlags = fiber.subtreeFlags & LayoutMask;
2519
+ if (primarySubtreeFlags !== NoFlags) {
2520
commitLayoutEffects(fiber.child, root, committedLanes);
2521
}
2522
}
@@ -2662,9 +2617,9 @@ export function enqueuePendingPassiveProfilerEffect(fiber: Fiber): void {
2617
function flushPassiveMountEffects(firstChild: Fiber): void {
2618
let fiber = firstChild;
2619
while (fiber !== null) {
2665
- const primarySubtreeFlags = fiber.subtreeFlags & PassiveSubtreeFlags;
2620
+ const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;
2621
2667
- if (fiber.child !== null && primarySubtreeFlags !== NoSubtreeFlags) {
2622
+ if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {
2623
flushPassiveMountEffects(fiber.child);
2624
}
2625
@@ -2698,8 +2653,8 @@ function flushPassiveUnmountEffects(firstChild: Fiber): void {
2653
// Note that this requires checking subtreeFlags of the current Fiber,
2654
// rather than the subtreeFlags/effectsTag of the first child,
2655
// since that would not cover passive effects in siblings.
2701
- const primarySubtreeFlags = fiber.subtreeFlags & PassiveSubtreeFlags;
2702
- if (primarySubtreeFlags !== NoSubtreeFlags) {
2656
+ const passiveFlags = fiber.subtreeFlags & PassiveMask;
2657
+ if (passiveFlags !== NoFlags) {
2658
flushPassiveUnmountEffects(child);
2659
}
2660
}
@@ -2719,10 +2674,7 @@ function flushPassiveUnmountEffectsInsideOfDeletedTree(
2674
fiberToDelete: Fiber,
2675
nearestMountedAncestor: Fiber,
2676
): void {
2722
- if (
2723
- (fiberToDelete.subtreeFlags & PassiveStaticSubtreeFlags) !==
2724
- NoSubtreeFlags
2725
- ) {
2677
+ if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {
2678
// If any children have passive effects then traverse the subtree.
2679
// Note that this requires checking subtreeFlags of the current Fiber,
2680
// rather than the subtreeFlags/effectsTag of the first child,
packages/react-reconciler/src/ReactInternalTypes.js
+1
-2
@@ -20,7 +20,6 @@ import type {SuspenseInstance} from './ReactFiberHostConfig';
20
import type {WorkTag} from './ReactWorkTags';
21
import type {TypeOfMode} from './ReactTypeOfMode';
22
import type {Flags} from './ReactFiberFlags';
23
-import type {SubtreeFlags} from './ReactSubtreeFlags';
23
import type {Lane, LanePriority, Lanes, LaneMap} from './ReactFiberLane';
24
import type {HookType} from './ReactFiberHooks.old';
25
import type {RootTag} from './ReactRootTags';
@@ -119,7 +118,7 @@ export type Fiber = {|
118
119
// Effect
120
flags: Flags,
122
- subtreeFlags: SubtreeFlags,
121
+ subtreeFlags: Flags,
122
deletions: Array<Fiber> | null,
123
124
// Singly linked list fast path to the next fiber with side-effects.
packages/react-reconciler/src/ReactSubtreeFlags.js
deleted
-18
@@ -1,18 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-// TODO: Move this to ReactFiberFlags so it's easier to line up the bits
11
-export type SubtreeFlags = number;
12
-
13
-export const NoFlags = /* */ 0b00000;
14
-export const BeforeMutation = /* */ 0b00001;
15
-export const Mutation = /* */ 0b00010;
16
-export const Layout = /* */ 0b00100;
17
-export const Passive = /* */ 0b01000;
18
-export const PassiveStatic = /* */ 0b10000;