98
Placement,
99
Update,
100
PlacementAndUpdate,
101
- Deletion,
101
Ref,
102
ContentReset,
103
Snapshot,
108
HostEffectMask,
109
Hydrating,
110
HydratingAndUpdate,
111
+ BeforeMutationMask,
112
+ MutationMask,
113
+ LayoutMask,
114
} from './ReactSideEffectTags';
115
+import {
116
+ NoEffect as NoSubtreeTag,
117
+ BeforeMutation,
118
+ Mutation,
119
+ Layout,
120
+} from './ReactSubtreeTags';
121
import {
122
NoLanePriority,
123
SyncLanePriority,
296
const FALLBACK_THROTTLE_MS: number = 500;
297
const DEFAULT_TIMEOUT_MS: number = 5000;
298
291
-let nextEffect: Fiber | null = null;
299
let hasUncaughtError = false;
300
let firstUncaughtError = null;
301
let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;
1751
// Mark the parent fiber as incomplete and clear its effect list.
1752
returnFiber.firstEffect = returnFiber.lastEffect = null;
1753
returnFiber.effectTag |= Incomplete;
1754
+ returnFiber.subtreeTag = NoSubtreeTag;
1755
+ returnFiber.deletions = null;
1756
}
1757
}
1758
1789
return;
1790
}
1791
1792
+ const didBailout =
1793
+ completedWork.alternate !== null &&
1794
+ completedWork.alternate.child === completedWork.child;
1795
+
1796
let newChildLanes = NoLanes;
1797
+ let subtreeTag = NoSubtreeTag;
1798
+
1799
+ if (!didBailout) {
1800
+ // Bubble up the earliest expiration time.
1801
+ if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
1802
+ // In profiling mode, resetChildExpirationTime is also used to reset
1803
+ // profiler durations.
1804
+ let actualDuration = completedWork.actualDuration;
1805
+ let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
1806
+
1807
+ let child = completedWork.child;
1808
+ while (child !== null) {
1809
+ newChildLanes = mergeLanes(
1810
+ newChildLanes,
1811
+ mergeLanes(child.lanes, child.childLanes),
1812
+ );
1813
1785
- // Bubble up the earliest expiration time.
1786
- if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
1787
- // In profiling mode, resetChildExpirationTime is also used to reset
1788
- // profiler durations.
1789
- let actualDuration = completedWork.actualDuration;
1790
- let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
1791
-
1792
- // When a fiber is cloned, its actualDuration is reset to 0. This value will
1793
- // only be updated if work is done on the fiber (i.e. it doesn't bailout).
1794
- // When work is done, it should bubble to the parent's actualDuration. If
1795
- // the fiber has not been cloned though, (meaning no work was done), then
1796
- // this value will reflect the amount of time spent working on a previous
1797
- // render. In that case it should not bubble. We determine whether it was
1798
- // cloned by comparing the child pointer.
1799
- const shouldBubbleActualDurations =
1800
- completedWork.alternate === null ||
1801
- completedWork.child !== completedWork.alternate.child;
1802
-
1803
- let child = completedWork.child;
1804
- while (child !== null) {
1805
- newChildLanes = mergeLanes(
1806
- newChildLanes,
1807
- mergeLanes(child.lanes, child.childLanes),
1808
- );
1809
- if (shouldBubbleActualDurations) {
1814
+ subtreeTag |= child.subtreeTag;
1815
+
1816
+ const effectTag = child.effectTag;
1817
+ if ((effectTag & BeforeMutationMask) !== NoEffect) {
1818
+ subtreeTag |= BeforeMutation;
1819
+ }
1820
+ if ((effectTag & MutationMask) !== NoEffect) {
1821
+ subtreeTag |= Mutation;
1822
+ }
1823
+ if ((effectTag & LayoutMask) !== NoEffect) {
1824
+ subtreeTag |= Layout;
1825
+ }
1826
+
1827
+ // When a fiber is cloned, its actualDuration is reset to 0. This value will
1828
+ // only be updated if work is done on the fiber (i.e. it doesn't bailout).
1829
+ // When work is done, it should bubble to the parent's actualDuration. If
1830
+ // the fiber has not been cloned though, (meaning no work was done), then
1831
+ // this value will reflect the amount of time spent working on a previous
1832
+ // render. In that case it should not bubble. We determine whether it was
1833
+ // cloned by comparing the child pointer.
1834
actualDuration += child.actualDuration;
1835
+
1836
+ treeBaseDuration += child.treeBaseDuration;
1837
+ child = child.sibling;
1838
+ }
1839
+
1840
+ const isTimedOutSuspense =
1841
+ completedWork.tag === SuspenseComponent &&
1842
+ completedWork.memoizedState !== null;
1843
+ if (isTimedOutSuspense) {
1844
+ // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1845
+ const primaryChildFragment = completedWork.child;
1846
+ if (primaryChildFragment !== null) {
1847
+ treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1848
+ }
1849
}
1812
- treeBaseDuration += child.treeBaseDuration;
1813
- child = child.sibling;
1814
- }
1850
1816
- const isTimedOutSuspense =
1817
- completedWork.tag === SuspenseComponent &&
1818
- completedWork.memoizedState !== null;
1819
- if (isTimedOutSuspense) {
1820
- // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1821
- const primaryChildFragment = completedWork.child;
1822
- if (primaryChildFragment !== null) {
1823
- treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1851
+ completedWork.actualDuration = actualDuration;
1852
+ completedWork.treeBaseDuration = treeBaseDuration;
1853
+ } else {
1854
+ let child = completedWork.child;
1855
+ while (child !== null) {
1856
+ newChildLanes = mergeLanes(
1857
+ newChildLanes,
1858
+ mergeLanes(child.lanes, child.childLanes),
1859
+ );
1860
+
1861
+ subtreeTag |= child.subtreeTag;
1862
+
1863
+ const effectTag = child.effectTag;
1864
+ if ((effectTag & BeforeMutationMask) !== NoEffect) {
1865
+ subtreeTag |= BeforeMutation;
1866
+ }
1867
+ if ((effectTag & MutationMask) !== NoEffect) {
1868
+ subtreeTag |= Mutation;
1869
+ }
1870
+ if ((effectTag & LayoutMask) !== NoEffect) {
1871
+ subtreeTag |= Layout;
1872
+ }
1873
+
1874
+ child = child.sibling;
1875
}
1876
}
1877
1827
- completedWork.actualDuration = actualDuration;
1828
- completedWork.treeBaseDuration = treeBaseDuration;
1878
+ completedWork.subtreeTag |= subtreeTag;
1879
} else {
1830
- let child = completedWork.child;
1831
- while (child !== null) {
1832
- newChildLanes = mergeLanes(
1833
- newChildLanes,
1834
- mergeLanes(child.lanes, child.childLanes),
1835
- );
1836
- child = child.sibling;
1880
+ // Bubble up the earliest expiration time.
1881
+ if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
1882
+ // In profiling mode, resetChildExpirationTime is also used to reset
1883
+ // profiler durations.
1884
+ let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
1885
+
1886
+ let child = completedWork.child;
1887
+ while (child !== null) {
1888
+ newChildLanes = mergeLanes(
1889
+ newChildLanes,
1890
+ mergeLanes(child.lanes, child.childLanes),
1891
+ );
1892
+
1893
+ treeBaseDuration += child.treeBaseDuration;
1894
+ child = child.sibling;
1895
+ }
1896
+
1897
+ const isTimedOutSuspense =
1898
+ completedWork.tag === SuspenseComponent &&
1899
+ completedWork.memoizedState !== null;
1900
+ if (isTimedOutSuspense) {
1901
+ // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1902
+ const primaryChildFragment = completedWork.child;
1903
+ if (primaryChildFragment !== null) {
1904
+ treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1905
+ }
1906
+ }
1907
+
1908
+ completedWork.treeBaseDuration = treeBaseDuration;
1909
+ } else {
1910
+ let child = completedWork.child;
1911
+ while (child !== null) {
1912
+ newChildLanes = mergeLanes(
1913
+ newChildLanes,
1914
+ mergeLanes(child.lanes, child.childLanes),
1915
+ );
1916
+
1917
+ child = child.sibling;
1918
+ }
1919
}
1920
}
1921
2034
focusedInstanceHandle = prepareForCommit(root.containerInfo);
2035
shouldFireAfterActiveInstanceBlur = false;
2036
1955
- nextEffect = firstEffect;
1956
- do {
1957
- if (__DEV__) {
1958
- invokeGuardedCallback(null, commitBeforeMutationEffects, null);
1959
- if (hasCaughtError()) {
1960
- invariant(nextEffect !== null, 'Should be working on an effect.');
1961
- const error = clearCaughtError();
1962
- captureCommitPhaseError(nextEffect, error);
1963
- nextEffect = nextEffect.nextEffect;
1964
- }
1965
- } else {
1966
- try {
1967
- commitBeforeMutationEffects();
1968
- } catch (error) {
1969
- invariant(nextEffect !== null, 'Should be working on an effect.');
1970
- captureCommitPhaseError(nextEffect, error);
1971
- nextEffect = nextEffect.nextEffect;
1972
- }
1973
- }
1974
- } while (nextEffect !== null);
2037
+ commitBeforeMutationEffects(finishedWork);
2038
2039
// We no longer need to track the active instance fiber
2040
focusedInstanceHandle = null;
2046
}
2047
2048
// The next phase is the mutation phase, where we mutate the host tree.
1986
- nextEffect = firstEffect;
1987
- do {
1988
- if (__DEV__) {
1989
- invokeGuardedCallback(
1990
- null,
1991
- commitMutationEffects,
1992
- null,
1993
- root,
1994
- renderPriorityLevel,
1995
- );
1996
- if (hasCaughtError()) {
1997
- invariant(nextEffect !== null, 'Should be working on an effect.');
1998
- const error = clearCaughtError();
1999
- captureCommitPhaseError(nextEffect, error);
2000
- nextEffect = nextEffect.nextEffect;
2001
- }
2002
- } else {
2003
- try {
2004
- commitMutationEffects(root, renderPriorityLevel);
2005
- } catch (error) {
2006
- invariant(nextEffect !== null, 'Should be working on an effect.');
2007
- captureCommitPhaseError(nextEffect, error);
2008
- nextEffect = nextEffect.nextEffect;
2009
- }
2010
- }
2011
- } while (nextEffect !== null);
2049
+ commitMutationEffects(finishedWork, root, renderPriorityLevel);
2050
2051
if (shouldFireAfterActiveInstanceBlur) {
2052
afterActiveInstanceBlur();
2062
// The next phase is the layout phase, where we call effects that read
2063
// the host tree after it's been mutated. The idiomatic use case for this is
2064
// layout, but class component lifecycles also fire here for legacy reasons.
2027
- nextEffect = firstEffect;
2028
- do {
2029
- if (__DEV__) {
2030
- invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);
2031
- if (hasCaughtError()) {
2032
- invariant(nextEffect !== null, 'Should be working on an effect.');
2033
- const error = clearCaughtError();
2034
- captureCommitPhaseError(nextEffect, error);
2035
- nextEffect = nextEffect.nextEffect;
2036
- }
2037
- } else {
2038
- try {
2039
- commitLayoutEffects(root, lanes);
2040
- } catch (error) {
2041
- invariant(nextEffect !== null, 'Should be working on an effect.');
2042
- captureCommitPhaseError(nextEffect, error);
2043
- nextEffect = nextEffect.nextEffect;
2044
- }
2045
- }
2046
- } while (nextEffect !== null);
2047
-
2048
- nextEffect = null;
2065
+ commitLayoutEffects(finishedWork, root, lanes);
2066
2067
// Tell Scheduler to yield at the end of the frame, so the browser has an
2068
// opportunity to paint.
2096
pendingPassiveEffectsLanes = lanes;
2097
pendingPassiveEffectsRenderPriority = renderPriorityLevel;
2098
} else {
2082
- // We are done with the effect chain at this point so let's clear the
2083
- // nextEffect pointers to assist with GC. If we have passive effects, we'll
2084
- // clear this in flushPassiveEffects.
2085
- nextEffect = firstEffect;
2086
- while (nextEffect !== null) {
2087
- const nextNextEffect = nextEffect.nextEffect;
2088
- nextEffect.nextEffect = null;
2089
- if (nextEffect.effectTag & Deletion) {
2090
- detachFiberAfterEffects(nextEffect);
2091
- }
2092
- nextEffect = nextNextEffect;
2093
- }
2099
+ // TODO (effects) Detach sibling pointers for deleted Fibers
2100
}
2101
2102
// Read this again, since an effect might have updated it
2178
return null;
2179
}
2180
2175
-function commitBeforeMutationEffects() {
2176
- while (nextEffect !== null) {
2177
- const current = nextEffect.alternate;
2181
+function commitBeforeMutationEffects(firstChild: Fiber) {
2182
+ let fiber = firstChild;
2183
+ while (fiber !== null) {
2184
+ if (fiber.deletions !== null) {
2185
+ commitBeforeMutationEffectsDeletions(fiber.deletions);
2186
+ }
2187
2179
- if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
2180
- if ((nextEffect.effectTag & Deletion) !== NoEffect) {
2181
- if (doesFiberContain(nextEffect, focusedInstanceHandle)) {
2182
- shouldFireAfterActiveInstanceBlur = true;
2183
- beforeActiveInstanceBlur();
2184
- }
2185
- } else {
2186
- // TODO: Move this out of the hot path using a dedicated effect tag.
2187
- if (
2188
- nextEffect.tag === SuspenseComponent &&
2189
- isSuspenseBoundaryBeingHidden(current, nextEffect) &&
2190
- doesFiberContain(nextEffect, focusedInstanceHandle)
2191
- ) {
2192
- shouldFireAfterActiveInstanceBlur = true;
2193
- beforeActiveInstanceBlur();
2194
- }
2188
+ if (fiber.child !== null) {
2189
+ const primarySubtreeTag = fiber.subtreeTag & BeforeMutation;
2190
+ if (primarySubtreeTag !== NoSubtreeTag) {
2191
+ commitBeforeMutationEffects(fiber.child);
2192
}
2193
}
2194
2198
- const effectTag = nextEffect.effectTag;
2199
- if ((effectTag & Snapshot) !== NoEffect) {
2200
- setCurrentDebugFiberInDEV(nextEffect);
2195
+ if (__DEV__) {
2196
+ setCurrentDebugFiberInDEV(fiber);
2197
+ invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);
2198
+ if (hasCaughtError()) {
2199
+ const error = clearCaughtError();
2200
+ captureCommitPhaseError(fiber, error);
2201
+ }
2202
+ resetCurrentDebugFiberInDEV();
2203
+ } else {
2204
+ try {
2205
+ commitBeforeMutationEffectsImpl(fiber);
2206
+ } catch (error) {
2207
+ captureCommitPhaseError(fiber, error);
2208
+ }
2209
+ }
2210
+ fiber = fiber.sibling;
2211
+ }
2212
+}
2213
2202
- commitBeforeMutationEffectOnFiber(current, nextEffect);
2214
+function commitBeforeMutationEffectsImpl(fiber: Fiber) {
2215
+ const current = fiber.alternate;
2216
+ const effectTag = fiber.effectTag;
2217
2204
- resetCurrentDebugFiberInDEV();
2218
+ if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
2219
+ // Check to see if the focused element was inside of a hidden (Suspense) subtree.
2220
+ // TODO: Move this out of the hot path using a dedicated effect tag.
2221
+ if (
2222
+ fiber.tag === SuspenseComponent &&
2223
+ isSuspenseBoundaryBeingHidden(current, fiber) &&
2224
+ doesFiberContain(fiber, focusedInstanceHandle)
2225
+ ) {
2226
+ shouldFireAfterActiveInstanceBlur = true;
2227
+ beforeActiveInstanceBlur();
2228
}
2206
- if ((effectTag & Passive) !== NoEffect) {
2207
- // If there are passive effects, schedule a callback to flush at
2208
- // the earliest opportunity.
2209
- if (!rootDoesHavePassiveEffects) {
2210
- rootDoesHavePassiveEffects = true;
2211
- scheduleCallback(NormalSchedulerPriority, () => {
2212
- flushPassiveEffects();
2213
- return null;
2214
- });
2215
- }
2229
+ }
2230
+
2231
+ if ((effectTag & Snapshot) !== NoEffect) {
2232
+ setCurrentDebugFiberInDEV(fiber);
2233
+ commitBeforeMutationEffectOnFiber(current, fiber);
2234
+ resetCurrentDebugFiberInDEV();
2235
+ }
2236
+
2237
+ if ((effectTag & Passive) !== NoEffect) {
2238
+ // If there are passive effects, schedule a callback to flush at
2239
+ // the earliest opportunity.
2240
+ if (!rootDoesHavePassiveEffects) {
2241
+ rootDoesHavePassiveEffects = true;
2242
+ scheduleCallback(NormalSchedulerPriority, () => {
2243
+ flushPassiveEffects();
2244
+ return null;
2245
+ });
2246
}
2217
- nextEffect = nextEffect.nextEffect;
2247
}
2248
}
2249
2221
-function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {
2222
- // TODO: Should probably move the bulk of this function to commitWork.
2223
- while (nextEffect !== null) {
2224
- setCurrentDebugFiberInDEV(nextEffect);
2250
+function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {
2251
+ for (let i = 0; i < deletions.length; i++) {
2252
+ const fiber = deletions[i];
2253
2226
- const effectTag = nextEffect.effectTag;
2254
+ // TODO (effects) It would be nice to avoid calling doesFiberContain()
2255
+ // Maybe we can repurpose one of the subtreeTag positions for this instead?
2256
+ // Use it to store which part of the tree the focused instance is in?
2257
+ // This assumes we can safely determine that instance during the "render" phase.
2258
2228
- if (effectTag & ContentReset) {
2229
- commitResetTextContent(nextEffect);
2259
+ if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {
2260
+ shouldFireAfterActiveInstanceBlur = true;
2261
+ beforeActiveInstanceBlur();
2262
}
2263
+ }
2264
+}
2265
2232
- if (effectTag & Ref) {
2233
- const current = nextEffect.alternate;
2234
- if (current !== null) {
2235
- commitDetachRef(current);
2236
- }
2237
- if (enableScopeAPI) {
2238
- // TODO: This is a temporary solution that allows us to transition away
2239
- // from React Flare on www.
2240
- if (nextEffect.tag === ScopeComponent) {
2241
- commitAttachRef(nextEffect);
2242
- }
2243
- }
2266
+function commitMutationEffects(
2267
+ firstChild: Fiber,
2268
+ root: FiberRoot,
2269
+ renderPriorityLevel,
2270
+) {
2271
+ let fiber = firstChild;
2272
+ while (fiber !== null) {
2273
+ if (fiber.deletions !== null) {
2274
+ commitMutationEffectsDeletions(
2275
+ fiber.deletions,
2276
+ root,
2277
+ renderPriorityLevel,
2278
+ );
2279
+
2280
+ // TODO (effects) Don't clear this yet; we may need to cleanup passive effects
2281
+ fiber.deletions = null;
2282
}
2283
2246
- // The following switch statement is only concerned about placement,
2247
- // updates, and deletions. To avoid needing to add a case for every possible
2248
- // bitmap value, we remove the secondary effects from the effect tag and
2249
- // switch on that value.
2250
- const primaryEffectTag =
2251
- effectTag & (Placement | Update | Deletion | Hydrating);
2252
- switch (primaryEffectTag) {
2253
- case Placement: {
2254
- commitPlacement(nextEffect);
2255
- // Clear the "placement" from effect tag so that we know that this is
2256
- // inserted, before any life-cycles like componentDidMount gets called.
2257
- // TODO: findDOMNode doesn't rely on this any more but isMounted does
2258
- // and isMounted is deprecated anyway so we should be able to kill this.
2259
- nextEffect.effectTag &= ~Placement;
2260
- break;
2284
+ if (fiber.child !== null) {
2285
+ const primarySubtreeTag = fiber.subtreeTag & Mutation;
2286
+ if (primarySubtreeTag !== NoSubtreeTag) {
2287
+ commitMutationEffects(fiber.child, root, renderPriorityLevel);
2288
}
2262
- case PlacementAndUpdate: {
2263
- // Placement
2264
- commitPlacement(nextEffect);
2265
- // Clear the "placement" from effect tag so that we know that this is
2266
- // inserted, before any life-cycles like componentDidMount gets called.
2267
- nextEffect.effectTag &= ~Placement;
2289
+ }
2290
2269
- // Update
2270
- const current = nextEffect.alternate;
2271
- commitWork(current, nextEffect);
2272
- break;
2291
+ if (__DEV__) {
2292
+ setCurrentDebugFiberInDEV(fiber);
2293
+ invokeGuardedCallback(
2294
+ null,
2295
+ commitMutationEffectsImpl,
2296
+ null,
2297
+ fiber,
2298
+ root,
2299
+ renderPriorityLevel,
2300
+ );
2301
+ if (hasCaughtError()) {
2302
+ const error = clearCaughtError();
2303
+ captureCommitPhaseError(fiber, error);
2304
}
2274
- case Hydrating: {
2275
- nextEffect.effectTag &= ~Hydrating;
2276
- break;
2305
+ resetCurrentDebugFiberInDEV();
2306
+ } else {
2307
+ try {
2308
+ commitMutationEffectsImpl(fiber, root, renderPriorityLevel);
2309
+ } catch (error) {
2310
+ captureCommitPhaseError(fiber, error);
2311
}
2278
- case HydratingAndUpdate: {
2279
- nextEffect.effectTag &= ~Hydrating;
2312
+ }
2313
+ fiber = fiber.sibling;
2314
+ }
2315
+}
2316
2281
- // Update
2282
- const current = nextEffect.alternate;
2283
- commitWork(current, nextEffect);
2284
- break;
2285
- }
2286
- case Update: {
2287
- const current = nextEffect.alternate;
2288
- commitWork(current, nextEffect);
2289
- break;
2290
- }
2291
- case Deletion: {
2292
- commitDeletion(root, nextEffect, renderPriorityLevel);
2293
- break;
2317
+function commitMutationEffectsImpl(
2318
+ fiber: Fiber,
2319
+ root: FiberRoot,
2320
+ renderPriorityLevel,
2321
+) {
2322
+ const effectTag = fiber.effectTag;
2323
+ if (effectTag & ContentReset) {
2324
+ commitResetTextContent(fiber);
2325
+ }
2326
+
2327
+ if (effectTag & Ref) {
2328
+ const current = fiber.alternate;
2329
+ if (current !== null) {
2330
+ commitDetachRef(current);
2331
+ }
2332
+ if (enableScopeAPI) {
2333
+ // TODO: This is a temporary solution that allows us to transition away
2334
+ // from React Flare on www.
2335
+ if (fiber.tag === ScopeComponent) {
2336
+ commitAttachRef(fiber);
2337
}
2338
}
2339
+ }
2340
2297
- resetCurrentDebugFiberInDEV();
2298
- nextEffect = nextEffect.nextEffect;
2341
+ // The following switch statement is only concerned about placement,
2342
+ // updates, and deletions. To avoid needing to add a case for every possible
2343
+ // bitmap value, we remove the secondary effects from the effect tag and
2344
+ // switch on that value.
2345
+ const primaryEffectTag = effectTag & (Placement | Update | Hydrating);
2346
+ switch (primaryEffectTag) {
2347
+ case Placement: {
2348
+ commitPlacement(fiber);
2349
+ // Clear the "placement" from effect tag so that we know that this is
2350
+ // inserted, before any life-cycles like componentDidMount gets called.
2351
+ // TODO: findDOMNode doesn't rely on this any more but isMounted does
2352
+ // and isMounted is deprecated anyway so we should be able to kill this.
2353
+ fiber.effectTag &= ~Placement;
2354
+ break;
2355
+ }
2356
+ case PlacementAndUpdate: {
2357
+ // Placement
2358
+ commitPlacement(fiber);
2359
+ // Clear the "placement" from effect tag so that we know that this is
2360
+ // inserted, before any life-cycles like componentDidMount gets called.
2361
+ fiber.effectTag &= ~Placement;
2362
+
2363
+ // Update
2364
+ const current = fiber.alternate;
2365
+ commitWork(current, fiber);
2366
+ break;
2367
+ }
2368
+ case Hydrating: {
2369
+ fiber.effectTag &= ~Hydrating;
2370
+ break;
2371
+ }
2372
+ case HydratingAndUpdate: {
2373
+ fiber.effectTag &= ~Hydrating;
2374
+
2375
+ // Update
2376
+ const current = fiber.alternate;
2377
+ commitWork(current, fiber);
2378
+ break;
2379
+ }
2380
+ case Update: {
2381
+ const current = fiber.alternate;
2382
+ commitWork(current, fiber);
2383
+ break;
2384
+ }
2385
}
2386
}
2387
2302
-function commitLayoutEffects(root: FiberRoot, committedLanes: Lanes) {
2303
- // TODO: Should probably move the bulk of this function to commitWork.
2304
- while (nextEffect !== null) {
2305
- setCurrentDebugFiberInDEV(nextEffect);
2306
-
2307
- const effectTag = nextEffect.effectTag;
2388
+function commitMutationEffectsDeletions(
2389
+ deletions: Array<Fiber>,
2390
+ root: FiberRoot,
2391
+ renderPriorityLevel,
2392
+) {
2393
+ for (let i = 0; i < deletions.length; i++) {
2394
+ const childToDelete = deletions[i];
2395
+ if (__DEV__) {
2396
+ invokeGuardedCallback(
2397
+ null,
2398
+ commitDeletion,
2399
+ null,
2400
+ root,
2401
+ childToDelete,
2402
+ renderPriorityLevel,
2403
+ );
2404
+ if (hasCaughtError()) {
2405
+ const error = clearCaughtError();
2406
+ captureCommitPhaseError(childToDelete, error);
2407
+ }
2408
+ } else {
2409
+ try {
2410
+ commitDeletion(root, childToDelete, renderPriorityLevel);
2411
+ } catch (error) {
2412
+ captureCommitPhaseError(childToDelete, error);
2413
+ }
2414
+ }
2415
+ // Don't clear the Deletion effect yet; we also use it to know when we need to detach refs later.
2416
+ }
2417
+}
2418
2309
- if (effectTag & (Update | Callback)) {
2310
- const current = nextEffect.alternate;
2311
- commitLayoutEffectOnFiber(root, current, nextEffect, committedLanes);
2419
+function commitLayoutEffects(
2420
+ firstChild: Fiber,
2421
+ root: FiberRoot,
2422
+ committedLanes: Lanes,
2423
+) {
2424
+ let fiber = firstChild;
2425
+ while (fiber !== null) {
2426
+ if (fiber.child !== null) {
2427
+ const primarySubtreeTag = fiber.subtreeTag & Layout;
2428
+ if (primarySubtreeTag !== NoSubtreeTag) {
2429
+ commitLayoutEffects(fiber.child, root, committedLanes);
2430
+ }
2431
}
2432
2314
- if (enableScopeAPI) {
2315
- // TODO: This is a temporary solution that allows us to transition away
2316
- // from React Flare on www.
2317
- if (effectTag & Ref && nextEffect.tag !== ScopeComponent) {
2318
- commitAttachRef(nextEffect);
2433
+ if (__DEV__) {
2434
+ setCurrentDebugFiberInDEV(fiber);
2435
+ invokeGuardedCallback(
2436
+ null,
2437
+ commitLayoutEffectsImpl,
2438
+ null,
2439
+ fiber,
2440
+ root,
2441
+ committedLanes,
2442
+ );
2443
+ if (hasCaughtError()) {
2444
+ const error = clearCaughtError();
2445
+ captureCommitPhaseError(fiber, error);
2446
}
2447
+ resetCurrentDebugFiberInDEV();
2448
} else {
2321
- if (effectTag & Ref) {
2322
- commitAttachRef(nextEffect);
2449
+ try {
2450
+ commitLayoutEffectsImpl(fiber, root, committedLanes);
2451
+ } catch (error) {
2452
+ captureCommitPhaseError(fiber, error);
2453
}
2454
}
2455
+ fiber = fiber.sibling;
2456
+ }
2457
+}
2458
2326
- resetCurrentDebugFiberInDEV();
2327
- nextEffect = nextEffect.nextEffect;
2459
+function commitLayoutEffectsImpl(
2460
+ fiber: Fiber,
2461
+ root: FiberRoot,
2462
+ committedLanes: Lanes,
2463
+) {
2464
+ const effectTag = fiber.effectTag;
2465
+
2466
+ setCurrentDebugFiberInDEV(fiber);
2467
+
2468
+ if (effectTag & (Update | Callback)) {
2469
+ const current = fiber.alternate;
2470
+ commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
2471
+ }
2472
+
2473
+ if (enableScopeAPI) {
2474
+ // TODO: This is a temporary solution that allows us to transition away
2475
+ // from React Flare on www.
2476
+ if (effectTag & Ref && fiber.tag !== ScopeComponent) {
2477
+ commitAttachRef(fiber);
2478
+ }
2479
+ } else {
2480
+ if (effectTag & Ref) {
2481
+ commitAttachRef(fiber);
2482
+ }
2483
}
2484
+
2485
+ resetCurrentDebugFiberInDEV();
2486
}
2487
2488
export function flushPassiveEffects() {
2696
}
2697
}
2698
2542
- // Note: This currently assumes there are no passive effects on the root fiber
2543
- // because the root is not part of its own effect list.
2544
- // This could change in the future.
2545
- let effect = root.current.firstEffect;
2546
- while (effect !== null) {
2547
- const nextNextEffect = effect.nextEffect;
2548
- // Remove nextEffect pointer to assist GC
2549
- effect.nextEffect = null;
2550
- if (effect.effectTag & Deletion) {
2551
- detachFiberAfterEffects(effect);
2552
- }
2553
- effect = nextNextEffect;
2554
- }
2699
+ // TODO (effects) Detach sibling pointers for deleted Fibers
2700
2701
if (enableProfilerTimer && enableProfilerCommitHooks) {
2702
const profilerEffects = pendingPassiveProfilerEffects;
3783
};
3784
}
3785
}
3641
-
3642
-function detachFiberAfterEffects(fiber: Fiber): void {
3643
- fiber.sibling = null;
3644
-}