react-reconciler 0.26.0-rc.2 → 0.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /** @license React v0.26.0-rc.2
1
+ /** @license React v0.26.2
2
2
  * react-reconciler.development.js
3
3
  *
4
4
  * Copyright (c) Facebook, Inc. and its affiliates.
@@ -268,7 +268,7 @@ function getComponentName(type) {
268
268
 
269
269
  // Don't change these two values. They're used by React Dev Tools.
270
270
  var NoFlags =
271
- /* */
271
+ /* */
272
272
  0;
273
273
  var PerformedWork =
274
274
  /* */
@@ -304,6 +304,10 @@ var Snapshot =
304
304
  var Passive =
305
305
  /* */
306
306
  512; // TODO (effects) Remove this bit once the new reconciler is synced to the old.
307
+
308
+ var PassiveUnmountPendingDev =
309
+ /* */
310
+ 8192;
307
311
  var Hydrating =
308
312
  /* */
309
313
  1024;
@@ -328,33 +332,6 @@ var ShouldCapture =
328
332
  var ForceUpdateForLegacySuspense =
329
333
  /* */
330
334
  16384; // Static tags describe aspects of a fiber that are not specific to a render,
331
- // e.g. a fiber uses a passive effect (even if there are no updates on this particular render).
332
- // This enables us to defer more work in the unmount case,
333
- // since we can defer traversing the tree during layout to look for Passive effects,
334
- // and instead rely on the static flag as a signal that there may be cleanup work.
335
-
336
- var PassiveStatic =
337
- /* */
338
- 32768; // Union of side effect groupings as pertains to subtreeFlags
339
-
340
- var BeforeMutationMask =
341
- /* */
342
- 778;
343
- var MutationMask =
344
- /* */
345
- 1182;
346
- var LayoutMask =
347
- /* */
348
- 164;
349
- var PassiveMask =
350
- /* */
351
- 520; // Union of tags that don't get reset on clones.
352
- // This allows certain concepts to persist without recalculting them,
353
- // e.g. whether a subtree contains passive effects or portals.
354
-
355
- var StaticMask =
356
- /* */
357
- 32768;
358
335
 
359
336
  // Filter certain DOM attributes (e.g. src, href) if their values are empty strings.
360
337
 
@@ -2295,7 +2272,15 @@ function higherPriorityLane(a, b) {
2295
2272
  return a !== NoLane && a < b ? a : b;
2296
2273
  }
2297
2274
  function createLaneMap(initial) {
2298
- return new Array(TotalLanes).fill(initial);
2275
+ // Intentionally pushing one by one.
2276
+ // https://v8.dev/blog/elements-kinds#avoid-creating-holes
2277
+ var laneMap = [];
2278
+
2279
+ for (var i = 0; i < TotalLanes; i++) {
2280
+ laneMap.push(initial);
2281
+ }
2282
+
2283
+ return laneMap;
2299
2284
  }
2300
2285
  function markRootUpdated(root, updateLane, eventTime) {
2301
2286
  root.pendingLanes |= updateLane; // TODO: Theoretically, any update to any lane can unblock any other lane. But
@@ -2540,7 +2525,7 @@ function flushSyncCallbackQueue() {
2540
2525
  Scheduler_cancelCallback(node);
2541
2526
  }
2542
2527
 
2543
- return flushSyncCallbackQueueImpl();
2528
+ flushSyncCallbackQueueImpl();
2544
2529
  }
2545
2530
 
2546
2531
  function flushSyncCallbackQueueImpl() {
@@ -2576,28 +2561,9 @@ function flushSyncCallbackQueueImpl() {
2576
2561
  isFlushingSyncQueue = false;
2577
2562
  }
2578
2563
  }
2579
-
2580
- return true;
2581
- } else {
2582
- return false;
2583
2564
  }
2584
2565
  }
2585
2566
 
2586
- var NoFlags$1 =
2587
- /* */
2588
- 0; // Represents whether effect should fire.
2589
-
2590
- var HasEffect =
2591
- /* */
2592
- 1; // Represents the phase in which the effect (not the clean-up) fires.
2593
-
2594
- var Layout =
2595
- /* */
2596
- 2;
2597
- var Passive$1 =
2598
- /* */
2599
- 4;
2600
-
2601
2567
  var NoMode = 0;
2602
2568
  var StrictMode = 1; // TODO: Remove BlockingMode and ConcurrentMode by reading from the root
2603
2569
  // tag instead
@@ -2807,7 +2773,7 @@ var ReactStrictModeWarnings = {
2807
2773
  var didWarnAboutUnsafeLifecycles = new Set();
2808
2774
 
2809
2775
  ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function (fiber, instance) {
2810
- // Dedupe strategy: Warn once per component.
2776
+ // Dedup strategy: Warn once per component.
2811
2777
  if (didWarnAboutUnsafeLifecycles.has(fiber.type)) {
2812
2778
  return;
2813
2779
  }
@@ -4672,16 +4638,24 @@ function ChildReconciler(shouldTrackSideEffects) {
4672
4638
  if (!shouldTrackSideEffects) {
4673
4639
  // Noop.
4674
4640
  return;
4675
- }
4641
+ } // Deletions are added in reversed order so we add it to the front.
4642
+ // At this point, the return fiber's effect list is empty except for
4643
+ // deletions, so we can just append the deletion to the list. The remaining
4644
+ // effects aren't added until the complete phase. Once we implement
4645
+ // resuming, this may not be true.
4646
+
4676
4647
 
4677
- var deletions = returnFiber.deletions;
4648
+ var last = returnFiber.lastEffect;
4678
4649
 
4679
- if (deletions === null) {
4680
- returnFiber.deletions = [childToDelete];
4681
- returnFiber.flags |= Deletion;
4650
+ if (last !== null) {
4651
+ last.nextEffect = childToDelete;
4652
+ returnFiber.lastEffect = childToDelete;
4682
4653
  } else {
4683
- deletions.push(childToDelete);
4654
+ returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
4684
4655
  }
4656
+
4657
+ childToDelete.nextEffect = null;
4658
+ childToDelete.flags = Deletion;
4685
4659
  }
4686
4660
 
4687
4661
  function deleteRemainingChildren(returnFiber, currentFirstChild) {
@@ -5737,13 +5711,6 @@ function popSuspenseContext(fiber) {
5737
5711
  pop(suspenseStackCursor, fiber);
5738
5712
  }
5739
5713
 
5740
- // A non-null SuspenseState means that it is blocked for one reason or another.
5741
- // - A non-null dehydrated field means it's blocked pending hydration.
5742
- // - A non-null dehydrated field can use isSuspenseInstancePending or
5743
- // isSuspenseInstanceFallback to query the reason for being dehydrated.
5744
- // - A null dehydrated field means it's blocked by something suspending and
5745
- // we're currently showing a fallback instead.
5746
-
5747
5714
  function shouldCaptureSuspense(workInProgress, hasInvisibleParent) {
5748
5715
  // If it was the primary children that just suspended, capture and render the
5749
5716
  // fallback. Otherwise, don't capture and bubble to the next boundary.
@@ -5825,6 +5792,21 @@ function findFirstSuspended(row) {
5825
5792
  return null;
5826
5793
  }
5827
5794
 
5795
+ var NoFlags$1 =
5796
+ /* */
5797
+ 0; // Represents whether effect should fire.
5798
+
5799
+ var HasEffect =
5800
+ /* */
5801
+ 1; // Represents the phase in which the effect (not the clean-up) fires.
5802
+
5803
+ var Layout =
5804
+ /* */
5805
+ 2;
5806
+ var Passive$1 =
5807
+ /* */
5808
+ 4;
5809
+
5828
5810
  // This may have been an insertion or a hydration.
5829
5811
 
5830
5812
  var hydrationParentFiber = null;
@@ -5859,14 +5841,17 @@ function deleteHydratableInstance(returnFiber, instance) {
5859
5841
  var childToDelete = createFiberFromHostInstanceForDeletion();
5860
5842
  childToDelete.stateNode = instance;
5861
5843
  childToDelete.return = returnFiber;
5862
- var deletions = returnFiber.deletions;
5863
-
5864
- if (deletions === null) {
5865
- returnFiber.deletions = [childToDelete]; // TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)
5866
-
5867
- returnFiber.flags |= Deletion;
5844
+ childToDelete.flags = Deletion; // This might seem like it belongs on progressedFirstDeletion. However,
5845
+ // these children are not part of the reconciliation list of children.
5846
+ // Even if we abort and rereconcile the children, that will try to hydrate
5847
+ // again and the nodes are still in the host tree so these will be
5848
+ // recreated.
5849
+
5850
+ if (returnFiber.lastEffect !== null) {
5851
+ returnFiber.lastEffect.nextEffect = childToDelete;
5852
+ returnFiber.lastEffect = childToDelete;
5868
5853
  } else {
5869
- deletions.push(childToDelete);
5854
+ returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
5870
5855
  }
5871
5856
  }
5872
5857
 
@@ -7175,7 +7160,7 @@ function mountEffect(create, deps) {
7175
7160
  }
7176
7161
  }
7177
7162
 
7178
- return mountEffectImpl(Passive | PassiveStatic, Passive$1, create, deps);
7163
+ return mountEffectImpl(Update | Passive, Passive$1, create, deps);
7179
7164
  }
7180
7165
 
7181
7166
  function updateEffect(create, deps) {
@@ -7186,7 +7171,7 @@ function updateEffect(create, deps) {
7186
7171
  }
7187
7172
  }
7188
7173
 
7189
- return updateEffectImpl(Passive, Passive$1, create, deps);
7174
+ return updateEffectImpl(Update | Passive, Passive$1, create, deps);
7190
7175
  }
7191
7176
 
7192
7177
  function mountLayoutEffect(create, deps) {
@@ -7469,7 +7454,7 @@ function mountOpaqueIdentifier() {
7469
7454
  var setId = mountState(id)[1];
7470
7455
 
7471
7456
  if ((currentlyRenderingFiber$1.mode & BlockingMode) === NoMode) {
7472
- currentlyRenderingFiber$1.flags |= Passive | PassiveStatic;
7457
+ currentlyRenderingFiber$1.flags |= Update | Passive;
7473
7458
  pushEffect(HasEffect | Passive$1, function () {
7474
7459
  setId(makeId());
7475
7460
  }, undefined, null);
@@ -8745,8 +8730,7 @@ function updateMode(current, workInProgress, renderLanes) {
8745
8730
 
8746
8731
  function updateProfiler(current, workInProgress, renderLanes) {
8747
8732
  {
8748
- // TODO: Only call onRender et al if subtree has effects
8749
- workInProgress.flags |= Update | Passive; // Reset effect durations for the next eventual effect phase.
8733
+ workInProgress.flags |= Update; // Reset effect durations for the next eventual effect phase.
8750
8734
  // These are reset during render to allow the DevTools commit hook a chance to read them,
8751
8735
 
8752
8736
  var stateNode = workInProgress.stateNode;
@@ -9407,7 +9391,8 @@ function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) {
9407
9391
  return {
9408
9392
  baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes)
9409
9393
  };
9410
- }
9394
+ } // TODO: Probably should inline this back
9395
+
9411
9396
 
9412
9397
  function shouldRemainOnFallback(suspenseContext, current, workInProgress, renderLanes) {
9413
9398
  // If we're already showing a fallback, there are cases where we need to
@@ -9498,17 +9483,41 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
9498
9483
  tryToClaimNextHydratableInstance(workInProgress); // This could've been a dehydrated suspense component.
9499
9484
  }
9500
9485
 
9486
+ var nextPrimaryChildren = nextProps.children;
9487
+ var nextFallbackChildren = nextProps.fallback;
9488
+
9501
9489
  if (showFallback) {
9502
- var nextPrimaryChildren = nextProps.children;
9503
- var nextFallbackChildren = nextProps.fallback;
9504
9490
  var fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes);
9505
9491
  var primaryChildFragment = workInProgress.child;
9506
9492
  primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes);
9507
9493
  workInProgress.memoizedState = SUSPENDED_MARKER;
9508
9494
  return fallbackFragment;
9495
+ } else if (typeof nextProps.unstable_expectedLoadTime === 'number') {
9496
+ // This is a CPU-bound tree. Skip this tree and show a placeholder to
9497
+ // unblock the surrounding content. Then immediately retry after the
9498
+ // initial commit.
9499
+ var _fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes);
9500
+
9501
+ var _primaryChildFragment = workInProgress.child;
9502
+ _primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes);
9503
+ workInProgress.memoizedState = SUSPENDED_MARKER; // Since nothing actually suspended, there will nothing to ping this to
9504
+ // get it started back up to attempt the next item. While in terms of
9505
+ // priority this work has the same priority as this current render, it's
9506
+ // not part of the same transition once the transition has committed. If
9507
+ // it's sync, we still want to yield so that it can be painted.
9508
+ // Conceptually, this is really the same as pinging. We can use any
9509
+ // RetryLane even if it's the one currently rendering since we're leaving
9510
+ // it behind on this node.
9511
+
9512
+ workInProgress.lanes = SomeRetryLane;
9513
+
9514
+ {
9515
+ markSpawnedWork(SomeRetryLane);
9516
+ }
9517
+
9518
+ return _fallbackFragment;
9509
9519
  } else {
9510
- var _nextPrimaryChildren = nextProps.children;
9511
- return mountSuspensePrimaryChildren(workInProgress, _nextPrimaryChildren, renderLanes);
9520
+ return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren, renderLanes);
9512
9521
  }
9513
9522
  } else {
9514
9523
  // This is an update.
@@ -9520,37 +9529,37 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
9520
9529
 
9521
9530
  if (showFallback) {
9522
9531
  var _nextFallbackChildren2 = nextProps.fallback;
9523
- var _nextPrimaryChildren3 = nextProps.children;
9532
+ var _nextPrimaryChildren2 = nextProps.children;
9524
9533
 
9525
- var _fallbackChildFragment = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren3, _nextFallbackChildren2, renderLanes);
9534
+ var _fallbackChildFragment = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren2, _nextFallbackChildren2, renderLanes);
9526
9535
 
9527
- var _primaryChildFragment2 = workInProgress.child;
9536
+ var _primaryChildFragment3 = workInProgress.child;
9528
9537
  var prevOffscreenState = current.child.memoizedState;
9529
- _primaryChildFragment2.memoizedState = prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
9530
- _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes);
9538
+ _primaryChildFragment3.memoizedState = prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
9539
+ _primaryChildFragment3.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes);
9531
9540
  workInProgress.memoizedState = SUSPENDED_MARKER;
9532
9541
  return _fallbackChildFragment;
9533
9542
  } else {
9534
- var _nextPrimaryChildren4 = nextProps.children;
9543
+ var _nextPrimaryChildren3 = nextProps.children;
9535
9544
 
9536
- var _primaryChildFragment3 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren4, renderLanes);
9545
+ var _primaryChildFragment4 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren3, renderLanes);
9537
9546
 
9538
9547
  workInProgress.memoizedState = null;
9539
- return _primaryChildFragment3;
9548
+ return _primaryChildFragment4;
9540
9549
  }
9541
9550
  } else {
9542
9551
  // The current tree is not already showing a fallback.
9543
9552
  if (showFallback) {
9544
9553
  // Timed out.
9545
9554
  var _nextFallbackChildren3 = nextProps.fallback;
9546
- var _nextPrimaryChildren5 = nextProps.children;
9555
+ var _nextPrimaryChildren4 = nextProps.children;
9547
9556
 
9548
- var _fallbackChildFragment2 = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren5, _nextFallbackChildren3, renderLanes);
9557
+ var _fallbackChildFragment2 = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren4, _nextFallbackChildren3, renderLanes);
9549
9558
 
9550
- var _primaryChildFragment4 = workInProgress.child;
9559
+ var _primaryChildFragment5 = workInProgress.child;
9551
9560
  var _prevOffscreenState = current.child.memoizedState;
9552
- _primaryChildFragment4.memoizedState = _prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(_prevOffscreenState, renderLanes);
9553
- _primaryChildFragment4.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes); // Skip the primary children, and continue working on the
9561
+ _primaryChildFragment5.memoizedState = _prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(_prevOffscreenState, renderLanes);
9562
+ _primaryChildFragment5.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes); // Skip the primary children, and continue working on the
9554
9563
  // fallback children.
9555
9564
 
9556
9565
  workInProgress.memoizedState = SUSPENDED_MARKER;
@@ -9558,12 +9567,12 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
9558
9567
  } else {
9559
9568
  // Still haven't timed out. Continue rendering the children, like we
9560
9569
  // normally do.
9561
- var _nextPrimaryChildren6 = nextProps.children;
9570
+ var _nextPrimaryChildren5 = nextProps.children;
9562
9571
 
9563
- var _primaryChildFragment5 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren6, renderLanes);
9572
+ var _primaryChildFragment6 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren5, renderLanes);
9564
9573
 
9565
9574
  workInProgress.memoizedState = null;
9566
- return _primaryChildFragment5;
9575
+ return _primaryChildFragment6;
9567
9576
  }
9568
9577
  }
9569
9578
  }
@@ -9645,15 +9654,9 @@ function updateSuspensePrimaryChildren(current, workInProgress, primaryChildren,
9645
9654
 
9646
9655
  if (currentFallbackChildFragment !== null) {
9647
9656
  // Delete the fallback child fragment
9648
- var deletions = workInProgress.deletions;
9649
-
9650
- if (deletions === null) {
9651
- workInProgress.deletions = [currentFallbackChildFragment]; // TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)
9652
-
9653
- workInProgress.flags |= Deletion;
9654
- } else {
9655
- deletions.push(currentFallbackChildFragment);
9656
- }
9657
+ currentFallbackChildFragment.nextEffect = null;
9658
+ currentFallbackChildFragment.flags = Deletion;
9659
+ workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChildFragment;
9657
9660
  }
9658
9661
 
9659
9662
  workInProgress.child = primaryChildFragment;
@@ -9695,16 +9698,24 @@ function updateSuspenseFallbackChildren(current, workInProgress, primaryChildren
9695
9698
  primaryChildFragment.treeBaseDuration = currentPrimaryChildFragment.treeBaseDuration;
9696
9699
  } // The fallback fiber was added as a deletion effect during the first pass.
9697
9700
  // However, since we're going to remain on the fallback, we no longer want
9698
- // to delete it.
9701
+ // to delete it. So we need to remove it from the list. Deletions are stored
9702
+ // on the same list as effects. We want to keep the effects from the primary
9703
+ // tree. So we copy the primary child fragment's effect list, which does not
9704
+ // include the fallback deletion effect.
9699
9705
 
9700
9706
 
9701
- workInProgress.deletions = null;
9702
- } else {
9703
- primaryChildFragment = createWorkInProgressOffscreenFiber(currentPrimaryChildFragment, primaryChildProps); // Since we're reusing a current tree, we need to reuse the flags, too.
9704
- // (We don't do this in legacy mode, because in legacy mode we don't re-use
9705
- // the current tree; see previous branch.)
9707
+ var progressedLastEffect = primaryChildFragment.lastEffect;
9706
9708
 
9707
- primaryChildFragment.subtreeFlags = currentPrimaryChildFragment.subtreeFlags & StaticMask;
9709
+ if (progressedLastEffect !== null) {
9710
+ workInProgress.firstEffect = primaryChildFragment.firstEffect;
9711
+ workInProgress.lastEffect = progressedLastEffect;
9712
+ progressedLastEffect.nextEffect = null;
9713
+ } else {
9714
+ // TODO: Reset this somewhere else? Lol legacy mode is so weird.
9715
+ workInProgress.firstEffect = workInProgress.lastEffect = null;
9716
+ }
9717
+ } else {
9718
+ primaryChildFragment = createWorkInProgressOffscreenFiber(currentPrimaryChildFragment, primaryChildProps);
9708
9719
  }
9709
9720
 
9710
9721
  var fallbackChildFragment;
@@ -9907,7 +9918,7 @@ function validateSuspenseListChildren(children, revealOrder) {
9907
9918
  }
9908
9919
  }
9909
9920
 
9910
- function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode) {
9921
+ function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode, lastEffectBeforeRendering) {
9911
9922
  var renderState = workInProgress.memoizedState;
9912
9923
 
9913
9924
  if (renderState === null) {
@@ -9917,7 +9928,8 @@ function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastCont
9917
9928
  renderingStartTime: 0,
9918
9929
  last: lastContentRow,
9919
9930
  tail: tail,
9920
- tailMode: tailMode
9931
+ tailMode: tailMode,
9932
+ lastEffect: lastEffectBeforeRendering
9921
9933
  };
9922
9934
  } else {
9923
9935
  // We can reuse the existing object from previous renders.
@@ -9927,6 +9939,7 @@ function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastCont
9927
9939
  renderState.last = lastContentRow;
9928
9940
  renderState.tail = tail;
9929
9941
  renderState.tailMode = tailMode;
9942
+ renderState.lastEffect = lastEffectBeforeRendering;
9930
9943
  }
9931
9944
  } // This can end up rendering this component multiple passes.
9932
9945
  // The first pass splits the children fibers into two sets. A head and tail.
@@ -9991,7 +10004,7 @@ function updateSuspenseListComponent(current, workInProgress, renderLanes) {
9991
10004
  }
9992
10005
 
9993
10006
  initSuspenseListRenderState(workInProgress, false, // isBackwards
9994
- tail, lastContentRow, tailMode);
10007
+ tail, lastContentRow, tailMode, workInProgress.lastEffect);
9995
10008
  break;
9996
10009
  }
9997
10010
 
@@ -10023,7 +10036,7 @@ function updateSuspenseListComponent(current, workInProgress, renderLanes) {
10023
10036
 
10024
10037
  initSuspenseListRenderState(workInProgress, true, // isBackwards
10025
10038
  _tail, null, // last
10026
- tailMode);
10039
+ tailMode, workInProgress.lastEffect);
10027
10040
  break;
10028
10041
  }
10029
10042
 
@@ -10032,7 +10045,7 @@ function updateSuspenseListComponent(current, workInProgress, renderLanes) {
10032
10045
  initSuspenseListRenderState(workInProgress, false, // isBackwards
10033
10046
  null, // tail
10034
10047
  null, // last
10035
- undefined);
10048
+ undefined, workInProgress.lastEffect);
10036
10049
  break;
10037
10050
  }
10038
10051
 
@@ -10238,16 +10251,17 @@ function remountFiber(current, oldWorkInProgress, newWorkInProgress) {
10238
10251
  // Since the old fiber is disconnected, we have to schedule it manually.
10239
10252
 
10240
10253
 
10241
- var deletions = returnFiber.deletions;
10254
+ var last = returnFiber.lastEffect;
10242
10255
 
10243
- if (deletions === null) {
10244
- returnFiber.deletions = [current]; // TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)
10245
-
10246
- returnFiber.flags |= Deletion;
10256
+ if (last !== null) {
10257
+ last.nextEffect = current;
10258
+ returnFiber.lastEffect = current;
10247
10259
  } else {
10248
- deletions.push(current);
10260
+ returnFiber.firstEffect = returnFiber.lastEffect = current;
10249
10261
  }
10250
10262
 
10263
+ current.nextEffect = null;
10264
+ current.flags = Deletion;
10251
10265
  newWorkInProgress.flags |= Placement; // Restart work from the new fiber.
10252
10266
 
10253
10267
  return newWorkInProgress;
@@ -10313,11 +10327,10 @@ function beginWork(current, workInProgress, renderLanes) {
10313
10327
  case Profiler:
10314
10328
  {
10315
10329
  // Profiler should only call onRender when one of its descendants actually rendered.
10316
- // TODO: Only call onRender et al if subtree has effects
10317
10330
  var hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes);
10318
10331
 
10319
10332
  if (hasChildWork) {
10320
- workInProgress.flags |= Passive | Update;
10333
+ workInProgress.flags |= Update;
10321
10334
  } // Reset effect durations for the next eventual effect phase.
10322
10335
  // These are reset during render to allow the DevTools commit hook a chance to read them,
10323
10336
 
@@ -10401,6 +10414,7 @@ function beginWork(current, workInProgress, renderLanes) {
10401
10414
  // update in the past but didn't complete it.
10402
10415
  renderState.rendering = null;
10403
10416
  renderState.tail = null;
10417
+ renderState.lastEffect = null;
10404
10418
  }
10405
10419
 
10406
10420
  pushSuspenseContext(workInProgress, suspenseStackCursor.current);
@@ -10614,30 +10628,6 @@ function markRef$1(workInProgress) {
10614
10628
  workInProgress.flags |= Ref;
10615
10629
  }
10616
10630
 
10617
- function hadNoMutationsEffects(current, completedWork) {
10618
- var didBailout = current !== null && current.child === completedWork.child;
10619
-
10620
- if (didBailout) {
10621
- return true;
10622
- }
10623
-
10624
- var child = completedWork.child;
10625
-
10626
- while (child !== null) {
10627
- if ((child.flags & MutationMask) !== NoFlags) {
10628
- return false;
10629
- }
10630
-
10631
- if ((child.subtreeFlags & MutationMask) !== NoFlags) {
10632
- return false;
10633
- }
10634
-
10635
- child = child.sibling;
10636
- }
10637
-
10638
- return true;
10639
- }
10640
-
10641
10631
  var appendAllChildren;
10642
10632
  var updateHostContainer;
10643
10633
  var updateHostComponent$1;
@@ -10676,7 +10666,7 @@ if (supportsMutation) {
10676
10666
  }
10677
10667
  };
10678
10668
 
10679
- updateHostContainer = function (current, workInProgress) {// Noop
10669
+ updateHostContainer = function (workInProgress) {// Noop
10680
10670
  };
10681
10671
 
10682
10672
  updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) {
@@ -10888,9 +10878,9 @@ if (supportsMutation) {
10888
10878
  }
10889
10879
  };
10890
10880
 
10891
- updateHostContainer = function (current, workInProgress) {
10881
+ updateHostContainer = function (workInProgress) {
10892
10882
  var portalOrRoot = workInProgress.stateNode;
10893
- var childrenUnchanged = hadNoMutationsEffects(current, workInProgress);
10883
+ var childrenUnchanged = workInProgress.firstEffect === null;
10894
10884
 
10895
10885
  if (childrenUnchanged) ; else {
10896
10886
  var container = portalOrRoot.containerInfo;
@@ -10909,7 +10899,7 @@ if (supportsMutation) {
10909
10899
  var oldProps = current.memoizedProps; // If there are no effects associated with this node, then none of our children had any updates.
10910
10900
  // This guarantees that we can reuse all of them.
10911
10901
 
10912
- var childrenUnchanged = hadNoMutationsEffects(current, workInProgress);
10902
+ var childrenUnchanged = workInProgress.firstEffect === null;
10913
10903
 
10914
10904
  if (childrenUnchanged && oldProps === newProps) {
10915
10905
  // No changes, just reuse the existing instance.
@@ -10967,7 +10957,7 @@ if (supportsMutation) {
10967
10957
  };
10968
10958
  } else {
10969
10959
  // No host operations
10970
- updateHostContainer = function (current, workInProgress) {// Noop
10960
+ updateHostContainer = function (workInProgress) {// Noop
10971
10961
  };
10972
10962
 
10973
10963
  updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) {// Noop
@@ -11057,92 +11047,6 @@ function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) {
11057
11047
  }
11058
11048
  }
11059
11049
 
11060
- function bubbleProperties(completedWork) {
11061
- var didBailout = completedWork.alternate !== null && completedWork.alternate.child === completedWork.child;
11062
- var newChildLanes = NoLanes;
11063
- var subtreeFlags = NoFlags;
11064
-
11065
- if (!didBailout) {
11066
- // Bubble up the earliest expiration time.
11067
- if ( (completedWork.mode & ProfileMode) !== NoMode) {
11068
- // In profiling mode, resetChildExpirationTime is also used to reset
11069
- // profiler durations.
11070
- var actualDuration = completedWork.actualDuration;
11071
- var treeBaseDuration = completedWork.selfBaseDuration;
11072
- var child = completedWork.child;
11073
-
11074
- while (child !== null) {
11075
- newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));
11076
- subtreeFlags |= child.subtreeFlags;
11077
- subtreeFlags |= child.flags; // When a fiber is cloned, its actualDuration is reset to 0. This value will
11078
- // only be updated if work is done on the fiber (i.e. it doesn't bailout).
11079
- // When work is done, it should bubble to the parent's actualDuration. If
11080
- // the fiber has not been cloned though, (meaning no work was done), then
11081
- // this value will reflect the amount of time spent working on a previous
11082
- // render. In that case it should not bubble. We determine whether it was
11083
- // cloned by comparing the child pointer.
11084
-
11085
- actualDuration += child.actualDuration;
11086
- treeBaseDuration += child.treeBaseDuration;
11087
- child = child.sibling;
11088
- }
11089
-
11090
- completedWork.actualDuration = actualDuration;
11091
- completedWork.treeBaseDuration = treeBaseDuration;
11092
- } else {
11093
- var _child = completedWork.child;
11094
-
11095
- while (_child !== null) {
11096
- newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));
11097
- subtreeFlags |= _child.subtreeFlags;
11098
- subtreeFlags |= _child.flags;
11099
- _child = _child.sibling;
11100
- }
11101
- }
11102
-
11103
- completedWork.subtreeFlags |= subtreeFlags;
11104
- } else {
11105
- // Bubble up the earliest expiration time.
11106
- if ( (completedWork.mode & ProfileMode) !== NoMode) {
11107
- // In profiling mode, resetChildExpirationTime is also used to reset
11108
- // profiler durations.
11109
- var _treeBaseDuration = completedWork.selfBaseDuration;
11110
- var _child2 = completedWork.child;
11111
-
11112
- while (_child2 !== null) {
11113
- newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child2.lanes, _child2.childLanes)); // "Static" flags share the lifetime of the fiber/hook they belong to,
11114
- // so we should bubble those up even during a bailout. All the other
11115
- // flags have a lifetime only of a single render + commit, so we should
11116
- // ignore them.
11117
-
11118
- subtreeFlags |= _child2.subtreeFlags & StaticMask;
11119
- subtreeFlags |= _child2.flags & StaticMask;
11120
- _treeBaseDuration += _child2.treeBaseDuration;
11121
- _child2 = _child2.sibling;
11122
- }
11123
-
11124
- completedWork.treeBaseDuration = _treeBaseDuration;
11125
- } else {
11126
- var _child3 = completedWork.child;
11127
-
11128
- while (_child3 !== null) {
11129
- newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child3.lanes, _child3.childLanes)); // "Static" flags share the lifetime of the fiber/hook they belong to,
11130
- // so we should bubble those up even during a bailout. All the other
11131
- // flags have a lifetime only of a single render + commit, so we should
11132
- // ignore them.
11133
-
11134
- subtreeFlags |= _child3.subtreeFlags & StaticMask;
11135
- subtreeFlags |= _child3.flags & StaticMask;
11136
- _child3 = _child3.sibling;
11137
- }
11138
- }
11139
-
11140
- completedWork.subtreeFlags |= subtreeFlags;
11141
- }
11142
-
11143
- completedWork.childLanes = newChildLanes;
11144
- }
11145
-
11146
11050
  function completeWork(current, workInProgress, renderLanes) {
11147
11051
  var newProps = workInProgress.pendingProps;
11148
11052
 
@@ -11157,7 +11061,6 @@ function completeWork(current, workInProgress, renderLanes) {
11157
11061
  case Profiler:
11158
11062
  case ContextConsumer:
11159
11063
  case MemoComponent:
11160
- bubbleProperties(workInProgress);
11161
11064
  return null;
11162
11065
 
11163
11066
  case ClassComponent:
@@ -11168,7 +11071,6 @@ function completeWork(current, workInProgress, renderLanes) {
11168
11071
  popContext(workInProgress);
11169
11072
  }
11170
11073
 
11171
- bubbleProperties(workInProgress);
11172
11074
  return null;
11173
11075
  }
11174
11076
 
@@ -11202,8 +11104,7 @@ function completeWork(current, workInProgress, renderLanes) {
11202
11104
  }
11203
11105
  }
11204
11106
 
11205
- updateHostContainer(current, workInProgress);
11206
- bubbleProperties(workInProgress);
11107
+ updateHostContainer(workInProgress);
11207
11108
  return null;
11208
11109
  }
11209
11110
 
@@ -11228,7 +11129,6 @@ function completeWork(current, workInProgress, renderLanes) {
11228
11129
  } // This can happen when we abort work.
11229
11130
 
11230
11131
 
11231
- bubbleProperties(workInProgress);
11232
11132
  return null;
11233
11133
  }
11234
11134
 
@@ -11265,7 +11165,6 @@ function completeWork(current, workInProgress, renderLanes) {
11265
11165
  }
11266
11166
  }
11267
11167
 
11268
- bubbleProperties(workInProgress);
11269
11168
  return null;
11270
11169
  }
11271
11170
 
@@ -11303,7 +11202,6 @@ function completeWork(current, workInProgress, renderLanes) {
11303
11202
  }
11304
11203
  }
11305
11204
 
11306
- bubbleProperties(workInProgress);
11307
11205
  return null;
11308
11206
  }
11309
11207
 
@@ -11318,8 +11216,7 @@ function completeWork(current, workInProgress, renderLanes) {
11318
11216
 
11319
11217
  if ( (workInProgress.mode & ProfileMode) !== NoMode) {
11320
11218
  transferActualDuration(workInProgress);
11321
- } // Don't bubble properties in this case.
11322
-
11219
+ }
11323
11220
 
11324
11221
  return workInProgress;
11325
11222
  }
@@ -11386,40 +11283,22 @@ function completeWork(current, workInProgress, renderLanes) {
11386
11283
  }
11387
11284
  }
11388
11285
 
11389
- bubbleProperties(workInProgress);
11390
-
11391
- {
11392
- if ((workInProgress.mode & ProfileMode) !== NoMode) {
11393
- if (nextDidTimeout) {
11394
- // Don't count time spent in a timed out Suspense subtree as part of the base duration.
11395
- var _primaryChildFragment2 = workInProgress.child;
11396
-
11397
- if (_primaryChildFragment2 !== null) {
11398
- // $FlowFixMe Flow doens't support type casting in combiation with the -= operator
11399
- workInProgress.treeBaseDuration -= _primaryChildFragment2.treeBaseDuration;
11400
- }
11401
- }
11402
- }
11403
- }
11404
-
11405
11286
  return null;
11406
11287
  }
11407
11288
 
11408
11289
  case HostPortal:
11409
11290
  popHostContainer(workInProgress);
11410
- updateHostContainer(current, workInProgress);
11291
+ updateHostContainer(workInProgress);
11411
11292
 
11412
11293
  if (current === null) {
11413
11294
  preparePortalMount(workInProgress.stateNode.containerInfo);
11414
11295
  }
11415
11296
 
11416
- bubbleProperties(workInProgress);
11417
11297
  return null;
11418
11298
 
11419
11299
  case ContextProvider:
11420
11300
  // Pop provider fiber
11421
11301
  popProvider(workInProgress);
11422
- bubbleProperties(workInProgress);
11423
11302
  return null;
11424
11303
 
11425
11304
  case IncompleteClassComponent:
@@ -11432,7 +11311,6 @@ function completeWork(current, workInProgress, renderLanes) {
11432
11311
  popContext(workInProgress);
11433
11312
  }
11434
11313
 
11435
- bubbleProperties(workInProgress);
11436
11314
  return null;
11437
11315
  }
11438
11316
 
@@ -11444,7 +11322,6 @@ function completeWork(current, workInProgress, renderLanes) {
11444
11322
  if (renderState === null) {
11445
11323
  // We're running in the default, "independent" mode.
11446
11324
  // We don't do anything in this mode.
11447
- bubbleProperties(workInProgress);
11448
11325
  return null;
11449
11326
  }
11450
11327
 
@@ -11494,15 +11371,19 @@ function completeWork(current, workInProgress, renderLanes) {
11494
11371
  workInProgress.flags |= Update;
11495
11372
  } // Rerender the whole list, but this time, we'll force fallbacks
11496
11373
  // to stay in place.
11497
- // Reset the child fibers to their original state.
11374
+ // Reset the effect list before doing the second pass since that's now invalid.
11375
+
11376
+
11377
+ if (renderState.lastEffect === null) {
11378
+ workInProgress.firstEffect = null;
11379
+ }
11498
11380
 
11381
+ workInProgress.lastEffect = renderState.lastEffect; // Reset the child fibers to their original state.
11499
11382
 
11500
- workInProgress.subtreeFlags = NoFlags;
11501
11383
  resetChildFibers(workInProgress, renderLanes); // Set up the Suspense Context to force suspense and immediately
11502
11384
  // rerender the children.
11503
11385
 
11504
- pushSuspenseContext(workInProgress, setShallowSuspenseContext(suspenseStackCursor.current, ForceSuspenseFallback)); // Don't bubble properties in this case.
11505
-
11386
+ pushSuspenseContext(workInProgress, setShallowSuspenseContext(suspenseStackCursor.current, ForceSuspenseFallback));
11506
11387
  return workInProgress.child;
11507
11388
  }
11508
11389
 
@@ -11556,8 +11437,16 @@ function completeWork(current, workInProgress, renderLanes) {
11556
11437
 
11557
11438
  if (renderState.tail === null && renderState.tailMode === 'hidden' && !renderedTail.alternate && !getIsHydrating() // We don't cut it if we're hydrating.
11558
11439
  ) {
11559
- // We're done.
11560
- bubbleProperties(workInProgress);
11440
+ // We need to delete the row we just rendered.
11441
+ // Reset the effect list to what it was before we rendered this
11442
+ // child. The nested children have already appended themselves.
11443
+ var lastEffect = workInProgress.lastEffect = renderState.lastEffect; // Remove any effects that were appended after this point.
11444
+
11445
+ if (lastEffect !== null) {
11446
+ lastEffect.nextEffect = null;
11447
+ } // We're done.
11448
+
11449
+
11561
11450
  return null;
11562
11451
  }
11563
11452
  } else if ( // The time it took to render last row is greater than the remaining
@@ -11570,10 +11459,13 @@ function completeWork(current, workInProgress, renderLanes) {
11570
11459
  workInProgress.flags |= DidCapture;
11571
11460
  didSuspendAlready = true;
11572
11461
  cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this
11573
- // to get it started back up to attempt the next item. If we can show
11574
- // them, then they really have the same priority as this render.
11575
- // So we'll pick it back up the very next render pass once we've had
11576
- // an opportunity to yield for paint.
11462
+ // to get it started back up to attempt the next item. While in terms
11463
+ // of priority this work has the same priority as this current render,
11464
+ // it's not part of the same transition once the transition has
11465
+ // committed. If it's sync, we still want to yield so that it can be
11466
+ // painted. Conceptually, this is really the same as pinging.
11467
+ // We can use any RetryLane even if it's the one currently rendering
11468
+ // since we're leaving it behind on this node.
11577
11469
 
11578
11470
  workInProgress.lanes = SomeRetryLane;
11579
11471
 
@@ -11610,6 +11502,7 @@ function completeWork(current, workInProgress, renderLanes) {
11610
11502
  var next = renderState.tail;
11611
11503
  renderState.rendering = next;
11612
11504
  renderState.tail = next.sibling;
11505
+ renderState.lastEffect = workInProgress.lastEffect;
11613
11506
  renderState.renderingStartTime = now$1();
11614
11507
  next.sibling = null; // Restore the context.
11615
11508
  // TODO: We can probably just avoid popping it instead and only
@@ -11624,12 +11517,10 @@ function completeWork(current, workInProgress, renderLanes) {
11624
11517
  }
11625
11518
 
11626
11519
  pushSuspenseContext(workInProgress, suspenseContext); // Do a pass over the next row.
11627
- // Don't bubble properties in this case.
11628
11520
 
11629
11521
  return next;
11630
11522
  }
11631
11523
 
11632
- bubbleProperties(workInProgress);
11633
11524
  return null;
11634
11525
  }
11635
11526
 
@@ -11653,21 +11544,16 @@ function completeWork(current, workInProgress, renderLanes) {
11653
11544
  case LegacyHiddenComponent:
11654
11545
  {
11655
11546
  popRenderLanes(workInProgress);
11656
- var _nextState = workInProgress.memoizedState;
11657
- var nextIsHidden = _nextState !== null;
11658
11547
 
11659
11548
  if (current !== null) {
11549
+ var _nextState = workInProgress.memoizedState;
11660
11550
  var _prevState = current.memoizedState;
11661
11551
  var prevIsHidden = _prevState !== null;
11552
+ var nextIsHidden = _nextState !== null;
11662
11553
 
11663
11554
  if (prevIsHidden !== nextIsHidden && newProps.mode !== 'unstable-defer-without-hiding') {
11664
11555
  workInProgress.flags |= Update;
11665
11556
  }
11666
- } // Don't bubble properties for hidden children.
11667
-
11668
-
11669
- if (!nextIsHidden || includesSomeLane(subtreeRenderLanes, OffscreenLane) || (workInProgress.mode & ConcurrentMode) === NoMode) {
11670
- bubbleProperties(workInProgress);
11671
11557
  }
11672
11558
 
11673
11559
  return null;
@@ -12021,7 +11907,9 @@ function attachPingListener(root, wakeable, lanes) {
12021
11907
 
12022
11908
  function throwException(root, returnFiber, sourceFiber, value, rootRenderLanes) {
12023
11909
  // The source fiber did not complete.
12024
- sourceFiber.flags |= Incomplete;
11910
+ sourceFiber.flags |= Incomplete; // Its effect list is no longer valid.
11911
+
11912
+ sourceFiber.firstEffect = sourceFiber.lastEffect = null;
12025
11913
 
12026
11914
  if (value !== null && typeof value === 'object' && typeof value.then === 'function') {
12027
11915
  // This is a wakeable.
@@ -12439,18 +12327,18 @@ var callComponentWillUnmountWithTimer = function (current, instance) {
12439
12327
  }; // Capture errors so they don't interrupt unmounting.
12440
12328
 
12441
12329
 
12442
- function safelyCallComponentWillUnmount(current, instance, nearestMountedAncestor) {
12330
+ function safelyCallComponentWillUnmount(current, instance) {
12443
12331
  {
12444
12332
  invokeGuardedCallback(null, callComponentWillUnmountWithTimer, null, current, instance);
12445
12333
 
12446
12334
  if (hasCaughtError()) {
12447
12335
  var unmountError = clearCaughtError();
12448
- captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
12336
+ captureCommitPhaseError(current, unmountError);
12449
12337
  }
12450
12338
  }
12451
12339
  }
12452
12340
 
12453
- function safelyDetachRef(current, nearestMountedAncestor) {
12341
+ function safelyDetachRef(current) {
12454
12342
  var ref = current.ref;
12455
12343
 
12456
12344
  if (ref !== null) {
@@ -12460,7 +12348,7 @@ function safelyDetachRef(current, nearestMountedAncestor) {
12460
12348
 
12461
12349
  if (hasCaughtError()) {
12462
12350
  var refError = clearCaughtError();
12463
- captureCommitPhaseError(current, nearestMountedAncestor, refError);
12351
+ captureCommitPhaseError(current, refError);
12464
12352
  }
12465
12353
  }
12466
12354
  } else {
@@ -12469,13 +12357,13 @@ function safelyDetachRef(current, nearestMountedAncestor) {
12469
12357
  }
12470
12358
  }
12471
12359
 
12472
- function safelyCallDestroy(current, nearestMountedAncestor, destroy) {
12360
+ function safelyCallDestroy(current, destroy) {
12473
12361
  {
12474
12362
  invokeGuardedCallback(null, destroy, null);
12475
12363
 
12476
12364
  if (hasCaughtError()) {
12477
12365
  var error = clearCaughtError();
12478
- captureCommitPhaseError(current, nearestMountedAncestor, error);
12366
+ captureCommitPhaseError(current, error);
12479
12367
  }
12480
12368
  }
12481
12369
  }
@@ -12558,7 +12446,7 @@ function commitBeforeMutationLifeCycles(current, finishedWork) {
12558
12446
  }
12559
12447
  }
12560
12448
 
12561
- function commitHookEffectListUnmount(tag, finishedWork, nearestMountedAncestor) {
12449
+ function commitHookEffectListUnmount(tag, finishedWork) {
12562
12450
  var updateQueue = finishedWork.updateQueue;
12563
12451
  var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
12564
12452
 
@@ -12573,45 +12461,13 @@ function commitHookEffectListUnmount(tag, finishedWork, nearestMountedAncestor)
12573
12461
  effect.destroy = undefined;
12574
12462
 
12575
12463
  if (destroy !== undefined) {
12576
- safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);
12464
+ destroy();
12577
12465
  }
12578
12466
  }
12579
12467
 
12580
12468
  effect = effect.next;
12581
12469
  } while (effect !== firstEffect);
12582
12470
  }
12583
- } // TODO: Remove this duplication.
12584
-
12585
-
12586
- function commitHookEffectListUnmount2( // Tags to check for when deciding whether to unmount. e.g. to skip over layout effects
12587
- hookFlags, fiber, nearestMountedAncestor) {
12588
- var updateQueue = fiber.updateQueue;
12589
- var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
12590
-
12591
- if (lastEffect !== null) {
12592
- var firstEffect = lastEffect.next;
12593
- var effect = firstEffect;
12594
-
12595
- do {
12596
- var _effect = effect,
12597
- next = _effect.next,
12598
- tag = _effect.tag;
12599
-
12600
- if ((tag & hookFlags) === hookFlags) {
12601
- var destroy = effect.destroy;
12602
-
12603
- if (destroy !== undefined) {
12604
- effect.destroy = undefined;
12605
-
12606
- {
12607
- safelyCallDestroy(fiber, nearestMountedAncestor, destroy);
12608
- }
12609
- }
12610
- }
12611
-
12612
- effect = next;
12613
- } while (effect !== firstEffect);
12614
- }
12615
12471
  }
12616
12472
 
12617
12473
  function commitHookEffectListMount(tag, finishedWork) {
@@ -12652,14 +12508,8 @@ function commitHookEffectListMount(tag, finishedWork) {
12652
12508
  }
12653
12509
  }
12654
12510
 
12655
- function invokePassiveEffectCreate(effect) {
12656
- var create = effect.create;
12657
- effect.destroy = create();
12658
- } // TODO: Remove this duplication.
12659
-
12660
-
12661
- function commitHookEffectListMount2(fiber) {
12662
- var updateQueue = fiber.updateQueue;
12511
+ function schedulePassiveEffects(finishedWork) {
12512
+ var updateQueue = finishedWork.updateQueue;
12663
12513
  var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
12664
12514
 
12665
12515
  if (lastEffect !== null) {
@@ -12667,27 +12517,13 @@ function commitHookEffectListMount2(fiber) {
12667
12517
  var effect = firstEffect;
12668
12518
 
12669
12519
  do {
12670
- var _effect2 = effect,
12671
- next = _effect2.next,
12672
- tag = _effect2.tag;
12520
+ var _effect = effect,
12521
+ next = _effect.next,
12522
+ tag = _effect.tag;
12673
12523
 
12674
12524
  if ((tag & Passive$1) !== NoFlags$1 && (tag & HasEffect) !== NoFlags$1) {
12675
- {
12676
- {
12677
- invokeGuardedCallback(null, invokePassiveEffectCreate, null, effect);
12678
- }
12679
-
12680
- if (hasCaughtError()) {
12681
- if (!(fiber !== null)) {
12682
- {
12683
- throw Error( "Should be working on an effect." );
12684
- }
12685
- }
12686
-
12687
- var error = clearCaughtError();
12688
- captureCommitPhaseError(fiber, fiber.return, error);
12689
- }
12690
- }
12525
+ enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);
12526
+ enqueuePendingPassiveHookEffectMount(finishedWork, effect);
12691
12527
  }
12692
12528
 
12693
12529
  effect = next;
@@ -12710,10 +12546,7 @@ function commitLifeCycles(finishedRoot, current, finishedWork, committedLanes) {
12710
12546
  commitHookEffectListMount(Layout | HasEffect, finishedWork);
12711
12547
  }
12712
12548
 
12713
- if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) {
12714
- schedulePassiveEffectCallback();
12715
- }
12716
-
12549
+ schedulePassiveEffects(finishedWork);
12717
12550
  return;
12718
12551
  }
12719
12552
 
@@ -12979,7 +12812,7 @@ function commitDetachRef(current) {
12979
12812
  // interrupt deletion, so it's okay
12980
12813
 
12981
12814
 
12982
- function commitUnmount(finishedRoot, current, nearestMountedAncestor, renderPriorityLevel) {
12815
+ function commitUnmount(finishedRoot, current, renderPriorityLevel) {
12983
12816
  onCommitUnmount(current);
12984
12817
 
12985
12818
  switch (current.tag) {
@@ -12999,14 +12832,16 @@ function commitUnmount(finishedRoot, current, nearestMountedAncestor, renderPrio
12999
12832
  var effect = firstEffect;
13000
12833
 
13001
12834
  do {
13002
- var _effect3 = effect,
13003
- destroy = _effect3.destroy,
13004
- tag = _effect3.tag;
12835
+ var _effect2 = effect,
12836
+ destroy = _effect2.destroy,
12837
+ tag = _effect2.tag;
13005
12838
 
13006
12839
  if (destroy !== undefined) {
13007
- if ((tag & Layout) !== NoFlags$1) {
12840
+ if ((tag & Passive$1) !== NoFlags$1) {
12841
+ enqueuePendingPassiveHookEffectUnmount(current, effect);
12842
+ } else {
13008
12843
  {
13009
- safelyCallDestroy(current, nearestMountedAncestor, destroy);
12844
+ safelyCallDestroy(current, destroy);
13010
12845
  }
13011
12846
  }
13012
12847
  }
@@ -13021,11 +12856,11 @@ function commitUnmount(finishedRoot, current, nearestMountedAncestor, renderPrio
13021
12856
 
13022
12857
  case ClassComponent:
13023
12858
  {
13024
- safelyDetachRef(current, nearestMountedAncestor);
12859
+ safelyDetachRef(current);
13025
12860
  var instance = current.stateNode;
13026
12861
 
13027
12862
  if (typeof instance.componentWillUnmount === 'function') {
13028
- safelyCallComponentWillUnmount(current, instance, nearestMountedAncestor);
12863
+ safelyCallComponentWillUnmount(current, instance);
13029
12864
  }
13030
12865
 
13031
12866
  return;
@@ -13033,7 +12868,7 @@ function commitUnmount(finishedRoot, current, nearestMountedAncestor, renderPrio
13033
12868
 
13034
12869
  case HostComponent:
13035
12870
  {
13036
- safelyDetachRef(current, nearestMountedAncestor);
12871
+ safelyDetachRef(current);
13037
12872
  return;
13038
12873
  }
13039
12874
 
@@ -13043,7 +12878,7 @@ function commitUnmount(finishedRoot, current, nearestMountedAncestor, renderPrio
13043
12878
  // We are also not using this parent because
13044
12879
  // the portal will get pushed immediately.
13045
12880
  if (supportsMutation) {
13046
- unmountHostComponents(finishedRoot, current, nearestMountedAncestor);
12881
+ unmountHostComponents(finishedRoot, current);
13047
12882
  } else if (supportsPersistence) {
13048
12883
  emptyPortalContainer(current);
13049
12884
  }
@@ -13071,7 +12906,7 @@ function commitUnmount(finishedRoot, current, nearestMountedAncestor, renderPrio
13071
12906
  }
13072
12907
  }
13073
12908
 
13074
- function commitNestedUnmounts(finishedRoot, root, nearestMountedAncestor, renderPriorityLevel) {
12909
+ function commitNestedUnmounts(finishedRoot, root, renderPriorityLevel) {
13075
12910
  // While we're inside a removed host node we don't want to call
13076
12911
  // removeChild on the inner nodes because they're removed by the top
13077
12912
  // call anyway. We also want to call componentWillUnmount on all
@@ -13080,7 +12915,7 @@ function commitNestedUnmounts(finishedRoot, root, nearestMountedAncestor, render
13080
12915
  var node = root;
13081
12916
 
13082
12917
  while (true) {
13083
- commitUnmount(finishedRoot, node, nearestMountedAncestor); // Visit children because they may contain more composite or host nodes.
12918
+ commitUnmount(finishedRoot, node); // Visit children because they may contain more composite or host nodes.
13084
12919
  // Skip portals because commitUnmount() currently visits them recursively.
13085
12920
 
13086
12921
  if (node.child !== null && ( // If we use mutation we drill down into portals using commitUnmount above.
@@ -13109,26 +12944,33 @@ function commitNestedUnmounts(finishedRoot, root, nearestMountedAncestor, render
13109
12944
  }
13110
12945
 
13111
12946
  function detachFiberMutation(fiber) {
13112
- // Cut off the return pointer to disconnect it from the tree.
13113
- // This enables us to detect and warn against state updates on an unmounted component.
13114
- // It also prevents events from bubbling from within disconnected components.
13115
- //
13116
- // Ideally, we should also clear the child pointer of the parent alternate to let this
12947
+ // Cut off the return pointers to disconnect it from the tree. Ideally, we
12948
+ // should clear the child pointer of the parent alternate to let this
13117
12949
  // get GC:ed but we don't know which for sure which parent is the current
13118
- // one so we'll settle for GC:ing the subtree of this child.
13119
- // This child itself will be GC:ed when the parent updates the next time.
12950
+ // one so we'll settle for GC:ing the subtree of this child. This child
12951
+ // itself will be GC:ed when the parent updates the next time.
12952
+ // Note: we cannot null out sibling here, otherwise it can cause issues
12953
+ // with findDOMNode and how it requires the sibling field to carry out
12954
+ // traversal in a later effect. See PR #16820. We now clear the sibling
12955
+ // field after effects, see: detachFiberAfterEffects.
13120
12956
  //
13121
- // Note that we can't clear child or sibling pointers yet.
13122
- // They're needed for passive effects and for findDOMNode.
13123
- // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).
13124
- var alternate = fiber.alternate;
12957
+ // Don't disconnect stateNode now; it will be detached in detachFiberAfterEffects.
12958
+ // It may be required if the current component is an error boundary,
12959
+ // and one of its descendants throws while unmounting a passive effect.
12960
+ fiber.alternate = null;
12961
+ fiber.child = null;
12962
+ fiber.dependencies = null;
12963
+ fiber.firstEffect = null;
12964
+ fiber.lastEffect = null;
12965
+ fiber.memoizedProps = null;
12966
+ fiber.memoizedState = null;
12967
+ fiber.pendingProps = null;
12968
+ fiber.return = null;
12969
+ fiber.updateQueue = null;
13125
12970
 
13126
- if (alternate !== null) {
13127
- alternate.return = null;
13128
- fiber.alternate = null;
12971
+ {
12972
+ fiber._debugOwner = null;
13129
12973
  }
13130
-
13131
- fiber.return = null;
13132
12974
  }
13133
12975
 
13134
12976
  function emptyPortalContainer(current) {
@@ -13356,7 +13198,7 @@ function insertOrAppendPlacementNode(node, before, parent) {
13356
13198
  }
13357
13199
  }
13358
13200
 
13359
- function unmountHostComponents(finishedRoot, current, nearestMountedAncestor, renderPriorityLevel) {
13201
+ function unmountHostComponents(finishedRoot, current, renderPriorityLevel) {
13360
13202
  // We only have the top Fiber that was deleted but we need to recurse down its
13361
13203
  // children to find all the terminal nodes.
13362
13204
  var node = current; // Each iteration, currentParent is populated with node's host parent if not
@@ -13405,7 +13247,7 @@ function unmountHostComponents(finishedRoot, current, nearestMountedAncestor, re
13405
13247
  }
13406
13248
 
13407
13249
  if (node.tag === HostComponent || node.tag === HostText) {
13408
- commitNestedUnmounts(finishedRoot, node, nearestMountedAncestor); // After all the children have unmounted, it is now safe to remove the
13250
+ commitNestedUnmounts(finishedRoot, node); // After all the children have unmounted, it is now safe to remove the
13409
13251
  // node from the tree.
13410
13252
 
13411
13253
  if (currentParentIsContainer) {
@@ -13426,7 +13268,7 @@ function unmountHostComponents(finishedRoot, current, nearestMountedAncestor, re
13426
13268
  continue;
13427
13269
  }
13428
13270
  } else {
13429
- commitUnmount(finishedRoot, node, nearestMountedAncestor); // Visit children because we may find more host components below.
13271
+ commitUnmount(finishedRoot, node); // Visit children because we may find more host components below.
13430
13272
 
13431
13273
  if (node.child !== null) {
13432
13274
  node.child.return = node;
@@ -13458,14 +13300,14 @@ function unmountHostComponents(finishedRoot, current, nearestMountedAncestor, re
13458
13300
  }
13459
13301
  }
13460
13302
 
13461
- function commitDeletion(finishedRoot, current, nearestMountedAncestor, renderPriorityLevel) {
13303
+ function commitDeletion(finishedRoot, current, renderPriorityLevel) {
13462
13304
  if (supportsMutation) {
13463
13305
  // Recursively delete all host nodes from the parent.
13464
13306
  // Detach refs and call componentWillUnmount() on the whole subtree.
13465
- unmountHostComponents(finishedRoot, current, nearestMountedAncestor);
13307
+ unmountHostComponents(finishedRoot, current);
13466
13308
  } else {
13467
13309
  // Detach refs and call componentWillUnmount() on the whole subtree.
13468
- commitNestedUnmounts(finishedRoot, current, nearestMountedAncestor);
13310
+ commitNestedUnmounts(finishedRoot, current);
13469
13311
  }
13470
13312
 
13471
13313
  var alternate = current.alternate;
@@ -13491,7 +13333,7 @@ function commitWork(current, finishedWork) {
13491
13333
  // e.g. a destroy function in one component should never override a ref set
13492
13334
  // by a create function in another component during the same commit.
13493
13335
  {
13494
- commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return);
13336
+ commitHookEffectListUnmount(Layout | HasEffect, finishedWork);
13495
13337
  }
13496
13338
 
13497
13339
  return;
@@ -13554,7 +13396,7 @@ function commitWork(current, finishedWork) {
13554
13396
  // e.g. a destroy function in one component should never override a ref set
13555
13397
  // by a create function in another component during the same commit.
13556
13398
  {
13557
- commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return);
13399
+ commitHookEffectListUnmount(Layout | HasEffect, finishedWork);
13558
13400
  }
13559
13401
 
13560
13402
  return;
@@ -13776,42 +13618,6 @@ function commitResetTextContent(current) {
13776
13618
  resetTextContent(current.stateNode);
13777
13619
  }
13778
13620
 
13779
- function commitPassiveWork(finishedWork) {
13780
- switch (finishedWork.tag) {
13781
- case FunctionComponent:
13782
- case ForwardRef:
13783
- case SimpleMemoComponent:
13784
- case Block:
13785
- {
13786
- commitHookEffectListUnmount2(Passive$1 | HasEffect, finishedWork, finishedWork.return);
13787
- break;
13788
- }
13789
- }
13790
- }
13791
-
13792
- function commitPassiveUnmount(current, nearestMountedAncestor) {
13793
- switch (current.tag) {
13794
- case FunctionComponent:
13795
- case ForwardRef:
13796
- case SimpleMemoComponent:
13797
- case Block:
13798
- commitHookEffectListUnmount2(Passive$1, current, nearestMountedAncestor);
13799
- }
13800
- }
13801
-
13802
- function commitPassiveLifeCycles(finishedRoot, finishedWork) {
13803
- switch (finishedWork.tag) {
13804
- case FunctionComponent:
13805
- case ForwardRef:
13806
- case SimpleMemoComponent:
13807
- case Block:
13808
- {
13809
- commitHookEffectListMount2(finishedWork);
13810
- break;
13811
- }
13812
- }
13813
- }
13814
-
13815
13621
  var COMPONENT_TYPE = 0;
13816
13622
  var HAS_PSEUDO_CLASS_TYPE = 1;
13817
13623
  var ROLE_TYPE = 2;
@@ -14418,6 +14224,7 @@ function resetRenderTimer() {
14418
14224
  function getRenderTargetTime() {
14419
14225
  return workInProgressRootRenderTargetTime;
14420
14226
  }
14227
+ var nextEffect = null;
14421
14228
  var hasUncaughtError = false;
14422
14229
  var firstUncaughtError = null;
14423
14230
  var legacyErrorBoundariesThatAlreadyFailed = null;
@@ -14425,6 +14232,8 @@ var rootDoesHavePassiveEffects = false;
14425
14232
  var rootWithPendingPassiveEffects = null;
14426
14233
  var pendingPassiveEffectsRenderPriority = NoPriority$1;
14427
14234
  var pendingPassiveEffectsLanes = NoLanes;
14235
+ var pendingPassiveHookEffectsMount = [];
14236
+ var pendingPassiveHookEffectsUnmount = [];
14428
14237
  var rootsWithPendingDiscreteUpdates = null; // Use these to prevent an infinite loop of nested updates
14429
14238
 
14430
14239
  var NESTED_UPDATE_LIMIT = 50;
@@ -14747,7 +14556,7 @@ function ensureRootIsScheduled(root, currentTime) {
14747
14556
  // goes through Scheduler.
14748
14557
 
14749
14558
 
14750
- function performConcurrentWorkOnRoot(root, didTimeout) {
14559
+ function performConcurrentWorkOnRoot(root) {
14751
14560
  // Since we know we're in a React event, we can clear the current
14752
14561
  // event time. The next update will compute a new event time.
14753
14562
  currentEventTime = NoTimestamp;
@@ -14783,18 +14592,6 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
14783
14592
  if (lanes === NoLanes) {
14784
14593
  // Defensive coding. This is never expected to happen.
14785
14594
  return null;
14786
- } // TODO: We only check `didTimeout` defensively, to account for a Scheduler
14787
- // bug we're still investigating. Once the bug in Scheduler is fixed,
14788
- // we can remove this, since we track expiration ourselves.
14789
-
14790
-
14791
- if ( didTimeout) {
14792
- // Something expired. Flush synchronously until there's no expired
14793
- // work left.
14794
- markRootExpired(root, lanes); // This will schedule a synchronous callback.
14795
-
14796
- ensureRootIsScheduled(root, now$1());
14797
- return null;
14798
14595
  }
14799
14596
 
14800
14597
  var exitStatus = renderRootConcurrent(root, lanes);
@@ -15588,19 +15385,59 @@ function completeUnitOfWork(unitOfWork) {
15588
15385
  workInProgress = next;
15589
15386
  return;
15590
15387
  }
15591
- } else {
15592
- // This fiber did not complete because something threw. Pop values off
15593
- // the stack without entering the complete phase. If this is a boundary,
15594
- // capture values if possible.
15595
- var _next = unwindWork(completedWork); // Because this fiber did not complete, don't reset its expiration time.
15596
15388
 
15389
+ resetChildLanes(completedWork);
15597
15390
 
15598
- if (_next !== null) {
15599
- // If completing this work spawned new work, do that next. We'll come
15600
- // back here again.
15601
- // Since we're restarting, remove anything that is not a host effect
15602
- // from the effect tag.
15603
- _next.flags &= HostEffectMask;
15391
+ if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete
15392
+ (returnFiber.flags & Incomplete) === NoFlags) {
15393
+ // Append all the effects of the subtree and this fiber onto the effect
15394
+ // list of the parent. The completion order of the children affects the
15395
+ // side-effect order.
15396
+ if (returnFiber.firstEffect === null) {
15397
+ returnFiber.firstEffect = completedWork.firstEffect;
15398
+ }
15399
+
15400
+ if (completedWork.lastEffect !== null) {
15401
+ if (returnFiber.lastEffect !== null) {
15402
+ returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
15403
+ }
15404
+
15405
+ returnFiber.lastEffect = completedWork.lastEffect;
15406
+ } // If this fiber had side-effects, we append it AFTER the children's
15407
+ // side-effects. We can perform certain side-effects earlier if needed,
15408
+ // by doing multiple passes over the effect list. We don't want to
15409
+ // schedule our own side-effect on our own list because if end up
15410
+ // reusing children we'll schedule this effect onto itself since we're
15411
+ // at the end.
15412
+
15413
+
15414
+ var flags = completedWork.flags; // Skip both NoWork and PerformedWork tags when creating the effect
15415
+ // list. PerformedWork effect is read by React DevTools but shouldn't be
15416
+ // committed.
15417
+
15418
+ if (flags > PerformedWork) {
15419
+ if (returnFiber.lastEffect !== null) {
15420
+ returnFiber.lastEffect.nextEffect = completedWork;
15421
+ } else {
15422
+ returnFiber.firstEffect = completedWork;
15423
+ }
15424
+
15425
+ returnFiber.lastEffect = completedWork;
15426
+ }
15427
+ }
15428
+ } else {
15429
+ // This fiber did not complete because something threw. Pop values off
15430
+ // the stack without entering the complete phase. If this is a boundary,
15431
+ // capture values if possible.
15432
+ var _next = unwindWork(completedWork); // Because this fiber did not complete, don't reset its expiration time.
15433
+
15434
+
15435
+ if (_next !== null) {
15436
+ // If completing this work spawned new work, do that next. We'll come
15437
+ // back here again.
15438
+ // Since we're restarting, remove anything that is not a host effect
15439
+ // from the effect tag.
15440
+ _next.flags &= HostEffectMask;
15604
15441
  workInProgress = _next;
15605
15442
  return;
15606
15443
  }
@@ -15621,10 +15458,9 @@ function completeUnitOfWork(unitOfWork) {
15621
15458
  }
15622
15459
 
15623
15460
  if (returnFiber !== null) {
15624
- // Mark the parent fiber as incomplete
15461
+ // Mark the parent fiber as incomplete and clear its effect list.
15462
+ returnFiber.firstEffect = returnFiber.lastEffect = null;
15625
15463
  returnFiber.flags |= Incomplete;
15626
- returnFiber.subtreeFlags = NoFlags;
15627
- returnFiber.deletions = null;
15628
15464
  }
15629
15465
  }
15630
15466
 
@@ -15648,6 +15484,68 @@ function completeUnitOfWork(unitOfWork) {
15648
15484
  }
15649
15485
  }
15650
15486
 
15487
+ function resetChildLanes(completedWork) {
15488
+ if ( // TODO: Move this check out of the hot path by moving `resetChildLanes`
15489
+ // to switch statement in `completeWork`.
15490
+ (completedWork.tag === LegacyHiddenComponent || completedWork.tag === OffscreenComponent) && completedWork.memoizedState !== null && !includesSomeLane(subtreeRenderLanes, OffscreenLane) && (completedWork.mode & ConcurrentMode) !== NoLanes) {
15491
+ // The children of this component are hidden. Don't bubble their
15492
+ // expiration times.
15493
+ return;
15494
+ }
15495
+
15496
+ var newChildLanes = NoLanes; // Bubble up the earliest expiration time.
15497
+
15498
+ if ( (completedWork.mode & ProfileMode) !== NoMode) {
15499
+ // In profiling mode, resetChildExpirationTime is also used to reset
15500
+ // profiler durations.
15501
+ var actualDuration = completedWork.actualDuration;
15502
+ var treeBaseDuration = completedWork.selfBaseDuration; // When a fiber is cloned, its actualDuration is reset to 0. This value will
15503
+ // only be updated if work is done on the fiber (i.e. it doesn't bailout).
15504
+ // When work is done, it should bubble to the parent's actualDuration. If
15505
+ // the fiber has not been cloned though, (meaning no work was done), then
15506
+ // this value will reflect the amount of time spent working on a previous
15507
+ // render. In that case it should not bubble. We determine whether it was
15508
+ // cloned by comparing the child pointer.
15509
+
15510
+ var shouldBubbleActualDurations = completedWork.alternate === null || completedWork.child !== completedWork.alternate.child;
15511
+ var child = completedWork.child;
15512
+
15513
+ while (child !== null) {
15514
+ newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));
15515
+
15516
+ if (shouldBubbleActualDurations) {
15517
+ actualDuration += child.actualDuration;
15518
+ }
15519
+
15520
+ treeBaseDuration += child.treeBaseDuration;
15521
+ child = child.sibling;
15522
+ }
15523
+
15524
+ var isTimedOutSuspense = completedWork.tag === SuspenseComponent && completedWork.memoizedState !== null;
15525
+
15526
+ if (isTimedOutSuspense) {
15527
+ // Don't count time spent in a timed out Suspense subtree as part of the base duration.
15528
+ var primaryChildFragment = completedWork.child;
15529
+
15530
+ if (primaryChildFragment !== null) {
15531
+ treeBaseDuration -= primaryChildFragment.treeBaseDuration;
15532
+ }
15533
+ }
15534
+
15535
+ completedWork.actualDuration = actualDuration;
15536
+ completedWork.treeBaseDuration = treeBaseDuration;
15537
+ } else {
15538
+ var _child = completedWork.child;
15539
+
15540
+ while (_child !== null) {
15541
+ newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));
15542
+ _child = _child.sibling;
15543
+ }
15544
+ }
15545
+
15546
+ completedWork.childLanes = newChildLanes;
15547
+ }
15548
+
15651
15549
  function commitRoot(root) {
15652
15550
  var renderPriorityLevel = getCurrentPriorityLevel();
15653
15551
  runWithPriority(ImmediatePriority$1, commitRootImpl.bind(null, root, renderPriorityLevel));
@@ -15711,17 +15609,28 @@ function commitRootImpl(root, renderPriorityLevel) {
15711
15609
  workInProgressRoot = null;
15712
15610
  workInProgress = null;
15713
15611
  workInProgressRootRenderLanes = NoLanes;
15714
- } // Check if there are any effects in the whole tree.
15715
- // TODO: This is left over from the effect list implementation, where we had
15716
- // to check for the existence of `firstEffect` to satsify Flow. I think the
15717
- // only other reason this optimization exists is because it affects profiling.
15718
- // Reconsider whether this is necessary.
15612
+ } // Get the list of effects.
15719
15613
 
15720
15614
 
15721
- var subtreeHasEffects = (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags;
15722
- var rootHasEffect = (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags;
15615
+ var firstEffect;
15723
15616
 
15724
- if (subtreeHasEffects || rootHasEffect) {
15617
+ if (finishedWork.flags > PerformedWork) {
15618
+ // A fiber's effect list consists only of its children, not itself. So if
15619
+ // the root has an effect, we need to add it to the end of the list. The
15620
+ // resulting list is the set that would belong to the root's parent, if it
15621
+ // had one; that is, all the effects in the tree including the root.
15622
+ if (finishedWork.lastEffect !== null) {
15623
+ finishedWork.lastEffect.nextEffect = finishedWork;
15624
+ firstEffect = finishedWork.firstEffect;
15625
+ } else {
15626
+ firstEffect = finishedWork;
15627
+ }
15628
+ } else {
15629
+ // There is no effect on the root.
15630
+ firstEffect = finishedWork.firstEffect;
15631
+ }
15632
+
15633
+ if (firstEffect !== null) {
15725
15634
 
15726
15635
  var prevExecutionContext = executionContext;
15727
15636
  executionContext |= CommitContext;
@@ -15736,7 +15645,26 @@ function commitRootImpl(root, renderPriorityLevel) {
15736
15645
 
15737
15646
  focusedInstanceHandle = prepareForCommit(root.containerInfo);
15738
15647
  shouldFireAfterActiveInstanceBlur = false;
15739
- commitBeforeMutationEffects(finishedWork); // We no longer need to track the active instance fiber
15648
+ nextEffect = firstEffect;
15649
+
15650
+ do {
15651
+ {
15652
+ invokeGuardedCallback(null, commitBeforeMutationEffects, null);
15653
+
15654
+ if (hasCaughtError()) {
15655
+ if (!(nextEffect !== null)) {
15656
+ {
15657
+ throw Error( "Should be working on an effect." );
15658
+ }
15659
+ }
15660
+
15661
+ var error = clearCaughtError();
15662
+ captureCommitPhaseError(nextEffect, error);
15663
+ nextEffect = nextEffect.nextEffect;
15664
+ }
15665
+ }
15666
+ } while (nextEffect !== null); // We no longer need to track the active instance fiber
15667
+
15740
15668
 
15741
15669
  focusedInstanceHandle = null;
15742
15670
 
@@ -15747,7 +15675,26 @@ function commitRootImpl(root, renderPriorityLevel) {
15747
15675
  } // The next phase is the mutation phase, where we mutate the host tree.
15748
15676
 
15749
15677
 
15750
- commitMutationEffects(finishedWork, root, renderPriorityLevel);
15678
+ nextEffect = firstEffect;
15679
+
15680
+ do {
15681
+ {
15682
+ invokeGuardedCallback(null, commitMutationEffects, null, root, renderPriorityLevel);
15683
+
15684
+ if (hasCaughtError()) {
15685
+ if (!(nextEffect !== null)) {
15686
+ {
15687
+ throw Error( "Should be working on an effect." );
15688
+ }
15689
+ }
15690
+
15691
+ var _error = clearCaughtError();
15692
+
15693
+ captureCommitPhaseError(nextEffect, _error);
15694
+ nextEffect = nextEffect.nextEffect;
15695
+ }
15696
+ }
15697
+ } while (nextEffect !== null);
15751
15698
 
15752
15699
  if (shouldFireAfterActiveInstanceBlur) {
15753
15700
  afterActiveInstanceBlur();
@@ -15759,21 +15706,32 @@ function commitRootImpl(root, renderPriorityLevel) {
15759
15706
  // work is current during componentDidMount/Update.
15760
15707
 
15761
15708
  root.current = finishedWork; // The next phase is the layout phase, where we call effects that read
15709
+ // the host tree after it's been mutated. The idiomatic use case for this is
15710
+ // layout, but class component lifecycles also fire here for legacy reasons.
15762
15711
 
15763
- commitLayoutEffects(finishedWork, root, lanes);
15712
+ nextEffect = firstEffect;
15764
15713
 
15714
+ do {
15715
+ {
15716
+ invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);
15765
15717
 
15766
- if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags || (finishedWork.flags & PassiveMask) !== NoFlags) {
15767
- if (!rootDoesHavePassiveEffects) {
15768
- rootDoesHavePassiveEffects = true;
15769
- scheduleCallback(NormalPriority$1, function () {
15770
- flushPassiveEffects();
15771
- return null;
15772
- });
15718
+ if (hasCaughtError()) {
15719
+ if (!(nextEffect !== null)) {
15720
+ {
15721
+ throw Error( "Should be working on an effect." );
15722
+ }
15723
+ }
15724
+
15725
+ var _error2 = clearCaughtError();
15726
+
15727
+ captureCommitPhaseError(nextEffect, _error2);
15728
+ nextEffect = nextEffect.nextEffect;
15729
+ }
15773
15730
  }
15774
- } // Tell Scheduler to yield at the end of the frame, so the browser has an
15775
- // opportunity to paint.
15731
+ } while (nextEffect !== null);
15776
15732
 
15733
+ nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an
15734
+ // opportunity to paint.
15777
15735
 
15778
15736
  requestPaint();
15779
15737
 
@@ -15802,6 +15760,22 @@ function commitRootImpl(root, renderPriorityLevel) {
15802
15760
  rootWithPendingPassiveEffects = root;
15803
15761
  pendingPassiveEffectsLanes = lanes;
15804
15762
  pendingPassiveEffectsRenderPriority = renderPriorityLevel;
15763
+ } else {
15764
+ // We are done with the effect chain at this point so let's clear the
15765
+ // nextEffect pointers to assist with GC. If we have passive effects, we'll
15766
+ // clear this in flushPassiveEffects.
15767
+ nextEffect = firstEffect;
15768
+
15769
+ while (nextEffect !== null) {
15770
+ var nextNextEffect = nextEffect.nextEffect;
15771
+ nextEffect.nextEffect = null;
15772
+
15773
+ if (nextEffect.flags & Deletion) {
15774
+ detachFiberAfterEffects(nextEffect);
15775
+ }
15776
+
15777
+ nextEffect = nextNextEffect;
15778
+ }
15805
15779
  } // Read this again, since an effect might have updated it
15806
15780
 
15807
15781
 
@@ -15861,9 +15835,9 @@ function commitRootImpl(root, renderPriorityLevel) {
15861
15835
 
15862
15836
  if (hasUncaughtError) {
15863
15837
  hasUncaughtError = false;
15864
- var error = firstUncaughtError;
15838
+ var _error3 = firstUncaughtError;
15865
15839
  firstUncaughtError = null;
15866
- throw error;
15840
+ throw _error3;
15867
15841
  }
15868
15842
 
15869
15843
  if ((executionContext & LegacyUnbatchedContext) !== NoContext) {
@@ -15881,257 +15855,153 @@ function commitRootImpl(root, renderPriorityLevel) {
15881
15855
  return null;
15882
15856
  }
15883
15857
 
15884
- function commitBeforeMutationEffects(firstChild) {
15885
- var fiber = firstChild;
15886
-
15887
- while (fiber !== null) {
15888
- if (fiber.deletions !== null) {
15889
- commitBeforeMutationEffectsDeletions(fiber.deletions);
15890
- }
15891
-
15892
- if (fiber.child !== null) {
15893
- var primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;
15858
+ function commitBeforeMutationEffects() {
15859
+ while (nextEffect !== null) {
15860
+ var current = nextEffect.alternate;
15894
15861
 
15895
- if (primarySubtreeFlags !== NoFlags) {
15896
- commitBeforeMutationEffects(fiber.child);
15862
+ if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
15863
+ if ((nextEffect.flags & Deletion) !== NoFlags) {
15864
+ if (doesFiberContain(nextEffect, focusedInstanceHandle)) {
15865
+ shouldFireAfterActiveInstanceBlur = true;
15866
+ beforeActiveInstanceBlur();
15867
+ }
15868
+ } else {
15869
+ // TODO: Move this out of the hot path using a dedicated effect tag.
15870
+ if (nextEffect.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, nextEffect) && doesFiberContain(nextEffect, focusedInstanceHandle)) {
15871
+ shouldFireAfterActiveInstanceBlur = true;
15872
+ beforeActiveInstanceBlur();
15873
+ }
15897
15874
  }
15898
15875
  }
15899
15876
 
15900
- {
15901
- setCurrentFiber(fiber);
15902
- invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);
15903
-
15904
- if (hasCaughtError()) {
15905
- var error = clearCaughtError();
15906
- captureCommitPhaseError(fiber, fiber.return, error);
15907
- }
15877
+ var flags = nextEffect.flags;
15908
15878
 
15879
+ if ((flags & Snapshot) !== NoFlags) {
15880
+ setCurrentFiber(nextEffect);
15881
+ commitBeforeMutationLifeCycles(current, nextEffect);
15909
15882
  resetCurrentFiber();
15910
15883
  }
15911
15884
 
15912
- fiber = fiber.sibling;
15913
- }
15914
- }
15915
-
15916
- function commitBeforeMutationEffectsImpl(fiber) {
15917
- var current = fiber.alternate;
15918
- var flags = fiber.flags;
15919
-
15920
- if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
15921
- // Check to see if the focused element was inside of a hidden (Suspense) subtree.
15922
- // TODO: Move this out of the hot path using a dedicated effect tag.
15923
- if (fiber.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, fiber) && doesFiberContain(fiber, focusedInstanceHandle)) {
15924
- shouldFireAfterActiveInstanceBlur = true;
15925
- beforeActiveInstanceBlur();
15926
- }
15927
- }
15928
-
15929
- if ((flags & Snapshot) !== NoFlags) {
15930
- setCurrentFiber(fiber);
15931
- commitBeforeMutationLifeCycles(current, fiber);
15932
- resetCurrentFiber();
15933
- }
15934
-
15935
- if ((flags & Passive) !== NoFlags) {
15936
- // If there are passive effects, schedule a callback to flush at
15937
- // the earliest opportunity.
15938
- if (!rootDoesHavePassiveEffects) {
15939
- rootDoesHavePassiveEffects = true;
15940
- scheduleCallback(NormalPriority$1, function () {
15941
- flushPassiveEffects();
15942
- return null;
15943
- });
15944
- }
15945
- }
15946
- }
15947
-
15948
- function commitBeforeMutationEffectsDeletions(deletions) {
15949
- for (var i = 0; i < deletions.length; i++) {
15950
- var fiber = deletions[i]; // TODO (effects) It would be nice to avoid calling doesFiberContain()
15951
- // Maybe we can repurpose one of the subtreeFlags positions for this instead?
15952
- // Use it to store which part of the tree the focused instance is in?
15953
- // This assumes we can safely determine that instance during the "render" phase.
15954
-
15955
- if (doesFiberContain(fiber, focusedInstanceHandle)) {
15956
- shouldFireAfterActiveInstanceBlur = true;
15957
- beforeActiveInstanceBlur();
15958
- }
15959
- }
15960
- }
15961
-
15962
- function commitMutationEffects(firstChild, root, renderPriorityLevel) {
15963
- var fiber = firstChild;
15964
-
15965
- while (fiber !== null) {
15966
- var deletions = fiber.deletions;
15967
-
15968
- if (deletions !== null) {
15969
- commitMutationEffectsDeletions(deletions, fiber, root, renderPriorityLevel);
15970
- }
15971
-
15972
- if (fiber.child !== null) {
15973
- var mutationFlags = fiber.subtreeFlags & MutationMask;
15974
-
15975
- if (mutationFlags !== NoFlags) {
15976
- commitMutationEffects(fiber.child, root, renderPriorityLevel);
15977
- }
15978
- }
15979
-
15980
- {
15981
- setCurrentFiber(fiber);
15982
- invokeGuardedCallback(null, commitMutationEffectsImpl, null, fiber, root, renderPriorityLevel);
15983
-
15984
- if (hasCaughtError()) {
15985
- var error = clearCaughtError();
15986
- captureCommitPhaseError(fiber, fiber.return, error);
15885
+ if ((flags & Passive) !== NoFlags) {
15886
+ // If there are passive effects, schedule a callback to flush at
15887
+ // the earliest opportunity.
15888
+ if (!rootDoesHavePassiveEffects) {
15889
+ rootDoesHavePassiveEffects = true;
15890
+ scheduleCallback(NormalPriority$1, function () {
15891
+ flushPassiveEffects();
15892
+ return null;
15893
+ });
15987
15894
  }
15988
-
15989
- resetCurrentFiber();
15990
15895
  }
15991
15896
 
15992
- fiber = fiber.sibling;
15897
+ nextEffect = nextEffect.nextEffect;
15993
15898
  }
15994
15899
  }
15995
15900
 
15996
- function commitMutationEffectsImpl(fiber, root, renderPriorityLevel) {
15997
- var flags = fiber.flags;
15998
-
15999
- if (flags & ContentReset) {
16000
- commitResetTextContent(fiber);
16001
- }
15901
+ function commitMutationEffects(root, renderPriorityLevel) {
15902
+ // TODO: Should probably move the bulk of this function to commitWork.
15903
+ while (nextEffect !== null) {
15904
+ setCurrentFiber(nextEffect);
15905
+ var flags = nextEffect.flags;
16002
15906
 
16003
- if (flags & Ref) {
16004
- var current = fiber.alternate;
16005
-
16006
- if (current !== null) {
16007
- commitDetachRef(current);
15907
+ if (flags & ContentReset) {
15908
+ commitResetTextContent(nextEffect);
16008
15909
  }
16009
- } // The following switch statement is only concerned about placement,
16010
- // updates, and deletions. To avoid needing to add a case for every possible
16011
- // bitmap value, we remove the secondary effects from the effect tag and
16012
- // switch on that value.
16013
15910
 
15911
+ if (flags & Ref) {
15912
+ var current = nextEffect.alternate;
16014
15913
 
16015
- var primaryFlags = flags & (Placement | Update | Hydrating);
15914
+ if (current !== null) {
15915
+ commitDetachRef(current);
15916
+ }
15917
+ } // The following switch statement is only concerned about placement,
15918
+ // updates, and deletions. To avoid needing to add a case for every possible
15919
+ // bitmap value, we remove the secondary effects from the effect tag and
15920
+ // switch on that value.
16016
15921
 
16017
- switch (primaryFlags) {
16018
- case Placement:
16019
- {
16020
- commitPlacement(fiber); // Clear the "placement" from effect tag so that we know that this is
16021
- // inserted, before any life-cycles like componentDidMount gets called.
16022
- // TODO: findDOMNode doesn't rely on this any more but isMounted does
16023
- // and isMounted is deprecated anyway so we should be able to kill this.
16024
15922
 
16025
- fiber.flags &= ~Placement;
16026
- break;
16027
- }
15923
+ var primaryFlags = flags & (Placement | Update | Deletion | Hydrating);
16028
15924
 
16029
- case PlacementAndUpdate:
16030
- {
16031
- // Placement
16032
- commitPlacement(fiber); // Clear the "placement" from effect tag so that we know that this is
16033
- // inserted, before any life-cycles like componentDidMount gets called.
15925
+ switch (primaryFlags) {
15926
+ case Placement:
15927
+ {
15928
+ commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is
15929
+ // inserted, before any life-cycles like componentDidMount gets called.
15930
+ // TODO: findDOMNode doesn't rely on this any more but isMounted does
15931
+ // and isMounted is deprecated anyway so we should be able to kill this.
16034
15932
 
16035
- fiber.flags &= ~Placement; // Update
15933
+ nextEffect.flags &= ~Placement;
15934
+ break;
15935
+ }
16036
15936
 
16037
- var _current = fiber.alternate;
16038
- commitWork(_current, fiber);
16039
- break;
16040
- }
15937
+ case PlacementAndUpdate:
15938
+ {
15939
+ // Placement
15940
+ commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is
15941
+ // inserted, before any life-cycles like componentDidMount gets called.
16041
15942
 
16042
- case Hydrating:
16043
- {
16044
- fiber.flags &= ~Hydrating;
16045
- break;
16046
- }
15943
+ nextEffect.flags &= ~Placement; // Update
16047
15944
 
16048
- case HydratingAndUpdate:
16049
- {
16050
- fiber.flags &= ~Hydrating; // Update
15945
+ var _current = nextEffect.alternate;
15946
+ commitWork(_current, nextEffect);
15947
+ break;
15948
+ }
16051
15949
 
16052
- var _current2 = fiber.alternate;
16053
- commitWork(_current2, fiber);
16054
- break;
16055
- }
15950
+ case Hydrating:
15951
+ {
15952
+ nextEffect.flags &= ~Hydrating;
15953
+ break;
15954
+ }
16056
15955
 
16057
- case Update:
16058
- {
16059
- var _current3 = fiber.alternate;
16060
- commitWork(_current3, fiber);
16061
- break;
16062
- }
16063
- }
16064
- }
15956
+ case HydratingAndUpdate:
15957
+ {
15958
+ nextEffect.flags &= ~Hydrating; // Update
16065
15959
 
16066
- function commitMutationEffectsDeletions(deletions, nearestMountedAncestor, root, renderPriorityLevel) {
16067
- for (var i = 0; i < deletions.length; i++) {
16068
- var childToDelete = deletions[i];
15960
+ var _current2 = nextEffect.alternate;
15961
+ commitWork(_current2, nextEffect);
15962
+ break;
15963
+ }
16069
15964
 
16070
- {
16071
- invokeGuardedCallback(null, commitDeletion, null, root, childToDelete, nearestMountedAncestor, renderPriorityLevel);
15965
+ case Update:
15966
+ {
15967
+ var _current3 = nextEffect.alternate;
15968
+ commitWork(_current3, nextEffect);
15969
+ break;
15970
+ }
16072
15971
 
16073
- if (hasCaughtError()) {
16074
- var error = clearCaughtError();
16075
- captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);
16076
- }
15972
+ case Deletion:
15973
+ {
15974
+ commitDeletion(root, nextEffect);
15975
+ break;
15976
+ }
16077
15977
  }
16078
- }
16079
- }
16080
15978
 
16081
- function schedulePassiveEffectCallback() {
16082
- if (!rootDoesHavePassiveEffects) {
16083
- rootDoesHavePassiveEffects = true;
16084
- scheduleCallback(NormalPriority$1, function () {
16085
- flushPassiveEffects();
16086
- return null;
16087
- });
15979
+ resetCurrentFiber();
15980
+ nextEffect = nextEffect.nextEffect;
16088
15981
  }
16089
15982
  }
16090
15983
 
16091
- function commitLayoutEffects(firstChild, root, committedLanes) {
16092
- var fiber = firstChild;
15984
+ function commitLayoutEffects(root, committedLanes) {
16093
15985
 
16094
- while (fiber !== null) {
16095
- if (fiber.child !== null) {
16096
- var primarySubtreeFlags = fiber.subtreeFlags & LayoutMask;
16097
15986
 
16098
- if (primarySubtreeFlags !== NoFlags) {
16099
- commitLayoutEffects(fiber.child, root, committedLanes);
16100
- }
15987
+ while (nextEffect !== null) {
15988
+ setCurrentFiber(nextEffect);
15989
+ var flags = nextEffect.flags;
15990
+
15991
+ if (flags & (Update | Callback)) {
15992
+ var current = nextEffect.alternate;
15993
+ commitLifeCycles(root, current, nextEffect);
16101
15994
  }
16102
15995
 
16103
15996
  {
16104
- setCurrentFiber(fiber);
16105
- invokeGuardedCallback(null, commitLayoutEffectsImpl, null, fiber, root, committedLanes);
16106
-
16107
- if (hasCaughtError()) {
16108
- var error = clearCaughtError();
16109
- captureCommitPhaseError(fiber, fiber.return, error);
15997
+ if (flags & Ref) {
15998
+ commitAttachRef(nextEffect);
16110
15999
  }
16111
-
16112
- resetCurrentFiber();
16113
16000
  }
16114
16001
 
16115
- fiber = fiber.sibling;
16116
- }
16117
- }
16118
-
16119
- function commitLayoutEffectsImpl(fiber, root, committedLanes) {
16120
- var flags = fiber.flags;
16121
- setCurrentFiber(fiber);
16122
-
16123
- if (flags & (Update | Callback)) {
16124
- var current = fiber.alternate;
16125
- commitLifeCycles(root, current, fiber);
16126
- }
16127
-
16128
- {
16129
- if (flags & Ref) {
16130
- commitAttachRef(fiber);
16131
- }
16002
+ resetCurrentFiber();
16003
+ nextEffect = nextEffect.nextEffect;
16132
16004
  }
16133
-
16134
- resetCurrentFiber();
16135
16005
  }
16136
16006
 
16137
16007
  function flushPassiveEffects() {
@@ -16147,87 +16017,41 @@ function flushPassiveEffects() {
16147
16017
 
16148
16018
  return false;
16149
16019
  }
16020
+ function enqueuePendingPassiveHookEffectMount(fiber, effect) {
16021
+ pendingPassiveHookEffectsMount.push(effect, fiber);
16150
16022
 
16151
- function flushPassiveMountEffects(root, firstChild) {
16152
- var fiber = firstChild;
16153
-
16154
- while (fiber !== null) {
16155
- var primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;
16156
-
16157
- if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {
16158
- flushPassiveMountEffects(root, fiber.child);
16159
- }
16160
-
16161
- if ((fiber.flags & Passive) !== NoFlags) {
16162
- setCurrentFiber(fiber);
16163
- commitPassiveLifeCycles(root, fiber);
16164
- resetCurrentFiber();
16165
- }
16166
-
16167
- fiber = fiber.sibling;
16023
+ if (!rootDoesHavePassiveEffects) {
16024
+ rootDoesHavePassiveEffects = true;
16025
+ scheduleCallback(NormalPriority$1, function () {
16026
+ flushPassiveEffects();
16027
+ return null;
16028
+ });
16168
16029
  }
16169
16030
  }
16031
+ function enqueuePendingPassiveHookEffectUnmount(fiber, effect) {
16032
+ pendingPassiveHookEffectsUnmount.push(effect, fiber);
16170
16033
 
16171
- function flushPassiveUnmountEffects(firstChild) {
16172
- var fiber = firstChild;
16173
-
16174
- while (fiber !== null) {
16175
- var deletions = fiber.deletions;
16176
-
16177
- if (deletions !== null) {
16178
- for (var i = 0; i < deletions.length; i++) {
16179
- var fiberToDelete = deletions[i];
16180
- flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, fiber); // Now that passive effects have been processed, it's safe to detach lingering pointers.
16181
-
16182
- detachFiberAfterEffects(fiberToDelete);
16183
- }
16184
- }
16185
-
16186
- var child = fiber.child;
16187
-
16188
- if (child !== null) {
16189
- // If any children have passive effects then traverse the subtree.
16190
- // Note that this requires checking subtreeFlags of the current Fiber,
16191
- // rather than the subtreeFlags/effectsTag of the first child,
16192
- // since that would not cover passive effects in siblings.
16193
- var passiveFlags = fiber.subtreeFlags & PassiveMask;
16194
-
16195
- if (passiveFlags !== NoFlags) {
16196
- flushPassiveUnmountEffects(child);
16197
- }
16198
- }
16199
-
16200
- var primaryFlags = fiber.flags & Passive;
16034
+ {
16035
+ fiber.flags |= PassiveUnmountPendingDev;
16036
+ var alternate = fiber.alternate;
16201
16037
 
16202
- if (primaryFlags !== NoFlags) {
16203
- setCurrentFiber(fiber);
16204
- commitPassiveWork(fiber);
16205
- resetCurrentFiber();
16038
+ if (alternate !== null) {
16039
+ alternate.flags |= PassiveUnmountPendingDev;
16206
16040
  }
16207
-
16208
- fiber = fiber.sibling;
16209
16041
  }
16210
- }
16211
-
16212
- function flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, nearestMountedAncestor) {
16213
- if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {
16214
- // If any children have passive effects then traverse the subtree.
16215
- // Note that this requires checking subtreeFlags of the current Fiber,
16216
- // rather than the subtreeFlags/effectsTag of the first child,
16217
- // since that would not cover passive effects in siblings.
16218
- var child = fiberToDelete.child;
16219
16042
 
16220
- while (child !== null) {
16221
- flushPassiveUnmountEffectsInsideOfDeletedTree(child, nearestMountedAncestor);
16222
- child = child.sibling;
16223
- }
16043
+ if (!rootDoesHavePassiveEffects) {
16044
+ rootDoesHavePassiveEffects = true;
16045
+ scheduleCallback(NormalPriority$1, function () {
16046
+ flushPassiveEffects();
16047
+ return null;
16048
+ });
16224
16049
  }
16050
+ }
16225
16051
 
16226
- if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {
16227
- setCurrentFiber(fiberToDelete);
16228
- commitPassiveUnmount(fiberToDelete, nearestMountedAncestor);
16229
- resetCurrentFiber();
16230
- }
16052
+ function invokePassiveEffectCreate(effect) {
16053
+ var create = effect.create;
16054
+ effect.destroy = create();
16231
16055
  }
16232
16056
 
16233
16057
  function flushPassiveEffectsImpl() {
@@ -16258,9 +16082,97 @@ function flushPassiveEffectsImpl() {
16258
16082
  // e.g. a destroy function in one component may unintentionally override a ref
16259
16083
  // value set by a create function in another component.
16260
16084
  // Layout effects have the same constraint.
16085
+ // First pass: Destroy stale passive effects.
16086
+
16087
+ var unmountEffects = pendingPassiveHookEffectsUnmount;
16088
+ pendingPassiveHookEffectsUnmount = [];
16089
+
16090
+ for (var i = 0; i < unmountEffects.length; i += 2) {
16091
+ var _effect = unmountEffects[i];
16092
+ var fiber = unmountEffects[i + 1];
16093
+ var destroy = _effect.destroy;
16094
+ _effect.destroy = undefined;
16095
+
16096
+ {
16097
+ fiber.flags &= ~PassiveUnmountPendingDev;
16098
+ var alternate = fiber.alternate;
16099
+
16100
+ if (alternate !== null) {
16101
+ alternate.flags &= ~PassiveUnmountPendingDev;
16102
+ }
16103
+ }
16104
+
16105
+ if (typeof destroy === 'function') {
16106
+ {
16107
+ setCurrentFiber(fiber);
16108
+
16109
+ {
16110
+ invokeGuardedCallback(null, destroy, null);
16111
+ }
16261
16112
 
16262
- flushPassiveUnmountEffects(root.current);
16263
- flushPassiveMountEffects(root, root.current);
16113
+ if (hasCaughtError()) {
16114
+ if (!(fiber !== null)) {
16115
+ {
16116
+ throw Error( "Should be working on an effect." );
16117
+ }
16118
+ }
16119
+
16120
+ var error = clearCaughtError();
16121
+ captureCommitPhaseError(fiber, error);
16122
+ }
16123
+
16124
+ resetCurrentFiber();
16125
+ }
16126
+ }
16127
+ } // Second pass: Create new passive effects.
16128
+
16129
+
16130
+ var mountEffects = pendingPassiveHookEffectsMount;
16131
+ pendingPassiveHookEffectsMount = [];
16132
+
16133
+ for (var _i = 0; _i < mountEffects.length; _i += 2) {
16134
+ var _effect2 = mountEffects[_i];
16135
+ var _fiber = mountEffects[_i + 1];
16136
+
16137
+ {
16138
+ setCurrentFiber(_fiber);
16139
+
16140
+ {
16141
+ invokeGuardedCallback(null, invokePassiveEffectCreate, null, _effect2);
16142
+ }
16143
+
16144
+ if (hasCaughtError()) {
16145
+ if (!(_fiber !== null)) {
16146
+ {
16147
+ throw Error( "Should be working on an effect." );
16148
+ }
16149
+ }
16150
+
16151
+ var _error4 = clearCaughtError();
16152
+
16153
+ captureCommitPhaseError(_fiber, _error4);
16154
+ }
16155
+
16156
+ resetCurrentFiber();
16157
+ }
16158
+ } // Note: This currently assumes there are no passive effects on the root fiber
16159
+ // because the root is not part of its own effect list.
16160
+ // This could change in the future.
16161
+
16162
+
16163
+ var effect = root.current.firstEffect;
16164
+
16165
+ while (effect !== null) {
16166
+ var nextNextEffect = effect.nextEffect; // Remove nextEffect pointer to assist GC
16167
+
16168
+ effect.nextEffect = null;
16169
+
16170
+ if (effect.flags & Deletion) {
16171
+ detachFiberAfterEffects(effect);
16172
+ }
16173
+
16174
+ effect = nextNextEffect;
16175
+ }
16264
16176
 
16265
16177
  {
16266
16178
  popInteractions(prevInteractions);
@@ -16313,7 +16225,7 @@ function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) {
16313
16225
  }
16314
16226
  }
16315
16227
 
16316
- function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error) {
16228
+ function captureCommitPhaseError(sourceFiber, error) {
16317
16229
  if (sourceFiber.tag === HostRoot) {
16318
16230
  // Error was thrown at the root. There is no parent, so the root
16319
16231
  // itself should capture it.
@@ -16321,11 +16233,7 @@ function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error) {
16321
16233
  return;
16322
16234
  }
16323
16235
 
16324
- var fiber = null;
16325
-
16326
- {
16327
- fiber = nearestMountedAncestor;
16328
- }
16236
+ var fiber = sourceFiber.return;
16329
16237
 
16330
16238
  while (fiber !== null) {
16331
16239
  if (fiber.tag === HostRoot) {
@@ -16346,6 +16254,20 @@ function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error) {
16346
16254
  markRootUpdated(root, SyncLane, eventTime);
16347
16255
  ensureRootIsScheduled(root, eventTime);
16348
16256
  schedulePendingInteractions(root, SyncLane);
16257
+ } else {
16258
+ // This component has already been unmounted.
16259
+ // We can't schedule any follow up work for the root because the fiber is already unmounted,
16260
+ // but we can still call the log-only boundary so the error isn't swallowed.
16261
+ //
16262
+ // TODO This is only a temporary bandaid for the old reconciler fork.
16263
+ // We can delete this special case once the new fork is merged.
16264
+ if (typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {
16265
+ try {
16266
+ instance.componentDidCatch(error, errorInfo);
16267
+ } catch (errorToIgnore) {// TODO Ignore this error? Rethrow it?
16268
+ // This is kind of an edge case.
16269
+ }
16270
+ }
16349
16271
  }
16350
16272
 
16351
16273
  return;
@@ -16528,29 +16450,12 @@ function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {
16528
16450
  if (tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {
16529
16451
  // Only warn for user-defined components, not internal ones like Suspense.
16530
16452
  return;
16531
- }
16532
-
16533
- if ((fiber.flags & PassiveStatic) !== NoFlags) {
16534
- var updateQueue = fiber.updateQueue;
16453
+ } // If there are pending passive effects unmounts for this Fiber,
16454
+ // we can assume that they would have prevented this update.
16535
16455
 
16536
- if (updateQueue !== null) {
16537
- var lastEffect = updateQueue.lastEffect;
16538
16456
 
16539
- if (lastEffect !== null) {
16540
- var firstEffect = lastEffect.next;
16541
- var effect = firstEffect;
16542
-
16543
- do {
16544
- if (effect.destroy !== undefined) {
16545
- if ((effect.tag & Passive$1) !== NoFlags$1) {
16546
- return;
16547
- }
16548
- }
16549
-
16550
- effect = effect.next;
16551
- } while (effect !== firstEffect);
16552
- }
16553
- }
16457
+ if ((fiber.flags & PassiveUnmountPendingDev) !== NoFlags) {
16458
+ return;
16554
16459
  } // We show the whole stack but dedupe on the top component's name because
16555
16460
  // the problematic code almost always lies inside that component.
16556
16461
 
@@ -17057,21 +16962,8 @@ function act(callback) {
17057
16962
  }
17058
16963
 
17059
16964
  function detachFiberAfterEffects(fiber) {
17060
- // Null out fields to improve GC for references that may be lingering (e.g. DevTools).
17061
- // Note that we already cleared the return pointer in detachFiberMutation().
17062
- fiber.child = null;
17063
- fiber.deletions = null;
17064
- fiber.dependencies = null;
17065
- fiber.memoizedProps = null;
17066
- fiber.memoizedState = null;
17067
- fiber.pendingProps = null;
17068
16965
  fiber.sibling = null;
17069
16966
  fiber.stateNode = null;
17070
- fiber.updateQueue = null;
17071
-
17072
- {
17073
- fiber._debugOwner = null;
17074
- }
17075
16967
  }
17076
16968
 
17077
16969
  var resolveFamily = null; // $FlowFixMe Flow gets confused by a WeakSet feature check below.
@@ -17511,8 +17403,9 @@ function FiberNode(tag, pendingProps, key, mode) {
17511
17403
  this.mode = mode; // Effects
17512
17404
 
17513
17405
  this.flags = NoFlags;
17514
- this.subtreeFlags = NoFlags;
17515
- this.deletions = null;
17406
+ this.nextEffect = null;
17407
+ this.firstEffect = null;
17408
+ this.lastEffect = null;
17516
17409
  this.lanes = NoLanes;
17517
17410
  this.childLanes = NoLanes;
17518
17411
  this.alternate = null;
@@ -17629,9 +17522,13 @@ function createWorkInProgress(current, pendingProps) {
17629
17522
  workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type.
17630
17523
 
17631
17524
  workInProgress.type = current.type; // We already have an alternate.
17525
+ // Reset the effect tag.
17526
+
17527
+ workInProgress.flags = NoFlags; // The effect list is no longer valid.
17632
17528
 
17633
- workInProgress.subtreeFlags = NoFlags;
17634
- workInProgress.deletions = null;
17529
+ workInProgress.nextEffect = null;
17530
+ workInProgress.firstEffect = null;
17531
+ workInProgress.lastEffect = null;
17635
17532
 
17636
17533
  {
17637
17534
  // We intentionally reset, rather than copy, actualDuration & actualStartTime.
@@ -17641,11 +17538,8 @@ function createWorkInProgress(current, pendingProps) {
17641
17538
  workInProgress.actualDuration = 0;
17642
17539
  workInProgress.actualStartTime = -1;
17643
17540
  }
17644
- } // Reset all effects except static ones.
17645
- // Static effects are not specific to a render.
17646
-
17541
+ }
17647
17542
 
17648
- workInProgress.flags = current.flags & StaticMask;
17649
17543
  workInProgress.childLanes = current.childLanes;
17650
17544
  workInProgress.lanes = current.lanes;
17651
17545
  workInProgress.child = current.child;
@@ -17701,7 +17595,11 @@ function resetWorkInProgress(workInProgress, renderLanes) {
17701
17595
  // avoid doing another reconciliation.
17702
17596
  // Reset the effect tag but keep any Placement tags, since that's something
17703
17597
  // that child fiber is setting, not the reconciliation.
17704
- workInProgress.flags &= Placement;
17598
+ workInProgress.flags &= Placement; // The effect list is no longer valid.
17599
+
17600
+ workInProgress.nextEffect = null;
17601
+ workInProgress.firstEffect = null;
17602
+ workInProgress.lastEffect = null;
17705
17603
  var current = workInProgress.alternate;
17706
17604
 
17707
17605
  if (current === null) {
@@ -17709,7 +17607,6 @@ function resetWorkInProgress(workInProgress, renderLanes) {
17709
17607
  workInProgress.childLanes = NoLanes;
17710
17608
  workInProgress.lanes = renderLanes;
17711
17609
  workInProgress.child = null;
17712
- workInProgress.subtreeFlags = NoFlags;
17713
17610
  workInProgress.memoizedProps = null;
17714
17611
  workInProgress.memoizedState = null;
17715
17612
  workInProgress.updateQueue = null;
@@ -17727,8 +17624,6 @@ function resetWorkInProgress(workInProgress, renderLanes) {
17727
17624
  workInProgress.childLanes = current.childLanes;
17728
17625
  workInProgress.lanes = current.lanes;
17729
17626
  workInProgress.child = current.child;
17730
- workInProgress.subtreeFlags = current.subtreeFlags;
17731
- workInProgress.deletions = null;
17732
17627
  workInProgress.memoizedProps = current.memoizedProps;
17733
17628
  workInProgress.memoizedState = current.memoizedState;
17734
17629
  workInProgress.updateQueue = current.updateQueue; // Needed because Blocks store data on type.
@@ -18049,8 +17944,9 @@ function assignFiberPropertiesInDEV(target, source) {
18049
17944
  target.dependencies = source.dependencies;
18050
17945
  target.mode = source.mode;
18051
17946
  target.flags = source.flags;
18052
- target.subtreeFlags = source.subtreeFlags;
18053
- target.deletions = source.deletions;
17947
+ target.nextEffect = source.nextEffect;
17948
+ target.firstEffect = source.firstEffect;
17949
+ target.lastEffect = source.lastEffect;
18054
17950
  target.lanes = source.lanes;
18055
17951
  target.childLanes = source.childLanes;
18056
17952
  target.alternate = source.alternate;