1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import {REACT_STRICT_MODE_TYPE} from 'shared/ReactSymbols';
    
  11. 
    
  12. import type {Wakeable, Thenable} from 'shared/ReactTypes';
    
  13. import type {Fiber, FiberRoot} from './ReactInternalTypes';
    
  14. import type {Lanes, Lane} from './ReactFiberLane';
    
  15. import type {SuspenseState} from './ReactFiberSuspenseComponent';
    
  16. import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
    
  17. import type {EventPriority} from './ReactEventPriorities';
    
  18. import type {
    
  19.   PendingTransitionCallbacks,
    
  20.   PendingBoundaries,
    
  21.   Transition,
    
  22.   TransitionAbort,
    
  23. } from './ReactFiberTracingMarkerComponent';
    
  24. import type {OffscreenInstance} from './ReactFiberActivityComponent';
    
  25. import type {RenderTaskFn} from './ReactFiberRootScheduler';
    
  26. 
    
  27. import {
    
  28.   replayFailedUnitOfWorkWithInvokeGuardedCallback,
    
  29.   enableCreateEventHandleAPI,
    
  30.   enableProfilerTimer,
    
  31.   enableProfilerCommitHooks,
    
  32.   enableProfilerNestedUpdatePhase,
    
  33.   enableProfilerNestedUpdateScheduledHook,
    
  34.   enableDebugTracing,
    
  35.   enableSchedulingProfiler,
    
  36.   disableSchedulerTimeoutInWorkLoop,
    
  37.   enableUpdaterTracking,
    
  38.   enableCache,
    
  39.   enableTransitionTracing,
    
  40.   useModernStrictMode,
    
  41.   disableLegacyContext,
    
  42.   alwaysThrottleRetries,
    
  43. } from 'shared/ReactFeatureFlags';
    
  44. import ReactSharedInternals from 'shared/ReactSharedInternals';
    
  45. import is from 'shared/objectIs';
    
  46. 
    
  47. import {
    
  48.   // Aliased because `act` will override and push to an internal queue
    
  49.   scheduleCallback as Scheduler_scheduleCallback,
    
  50.   shouldYield,
    
  51.   requestPaint,
    
  52.   now,
    
  53.   NormalPriority as NormalSchedulerPriority,
    
  54.   IdlePriority as IdleSchedulerPriority,
    
  55. } from './Scheduler';
    
  56. import {
    
  57.   logCommitStarted,
    
  58.   logCommitStopped,
    
  59.   logLayoutEffectsStarted,
    
  60.   logLayoutEffectsStopped,
    
  61.   logPassiveEffectsStarted,
    
  62.   logPassiveEffectsStopped,
    
  63.   logRenderStarted,
    
  64.   logRenderStopped,
    
  65. } from './DebugTracing';
    
  66. 
    
  67. import {
    
  68.   resetAfterCommit,
    
  69.   scheduleTimeout,
    
  70.   cancelTimeout,
    
  71.   noTimeout,
    
  72.   afterActiveInstanceBlur,
    
  73.   getCurrentEventPriority,
    
  74.   errorHydratingContainer,
    
  75.   startSuspendingCommit,
    
  76.   waitForCommitToBeReady,
    
  77.   preloadInstance,
    
  78. } from './ReactFiberConfig';
    
  79. 
    
  80. import {
    
  81.   createWorkInProgress,
    
  82.   assignFiberPropertiesInDEV,
    
  83.   resetWorkInProgress,
    
  84. } from './ReactFiber';
    
  85. import {isRootDehydrated} from './ReactFiberShellHydration';
    
  86. import {
    
  87.   getIsHydrating,
    
  88.   didSuspendOrErrorWhileHydratingDEV,
    
  89. } from './ReactFiberHydrationContext';
    
  90. import {
    
  91.   NoMode,
    
  92.   ProfileMode,
    
  93.   ConcurrentMode,
    
  94.   StrictLegacyMode,
    
  95.   StrictEffectsMode,
    
  96.   NoStrictPassiveEffectsMode,
    
  97. } from './ReactTypeOfMode';
    
  98. import {
    
  99.   HostRoot,
    
  100.   IndeterminateComponent,
    
  101.   ClassComponent,
    
  102.   SuspenseComponent,
    
  103.   SuspenseListComponent,
    
  104.   OffscreenComponent,
    
  105.   FunctionComponent,
    
  106.   ForwardRef,
    
  107.   MemoComponent,
    
  108.   SimpleMemoComponent,
    
  109.   Profiler,
    
  110.   HostComponent,
    
  111.   HostHoistable,
    
  112.   HostSingleton,
    
  113. } from './ReactWorkTags';
    
  114. import {ConcurrentRoot, LegacyRoot} from './ReactRootTags';
    
  115. import type {Flags} from './ReactFiberFlags';
    
  116. import {
    
  117.   NoFlags,
    
  118.   Incomplete,
    
  119.   StoreConsistency,
    
  120.   HostEffectMask,
    
  121.   ForceClientRender,
    
  122.   BeforeMutationMask,
    
  123.   MutationMask,
    
  124.   LayoutMask,
    
  125.   PassiveMask,
    
  126.   PlacementDEV,
    
  127.   Visibility,
    
  128.   MountPassiveDev,
    
  129.   MountLayoutDev,
    
  130. } from './ReactFiberFlags';
    
  131. import {
    
  132.   NoLanes,
    
  133.   NoLane,
    
  134.   SyncLane,
    
  135.   claimNextRetryLane,
    
  136.   includesSyncLane,
    
  137.   isSubsetOfLanes,
    
  138.   mergeLanes,
    
  139.   removeLanes,
    
  140.   pickArbitraryLane,
    
  141.   includesNonIdleWork,
    
  142.   includesOnlyRetries,
    
  143.   includesOnlyTransitions,
    
  144.   includesBlockingLane,
    
  145.   includesExpiredLane,
    
  146.   getNextLanes,
    
  147.   getEntangledLanes,
    
  148.   getLanesToRetrySynchronouslyOnError,
    
  149.   markRootUpdated,
    
  150.   markRootSuspended as markRootSuspended_dontCallThisOneDirectly,
    
  151.   markRootPinged,
    
  152.   upgradePendingLanesToSync,
    
  153.   markRootFinished,
    
  154.   addFiberToLanesMap,
    
  155.   movePendingFibersToMemoized,
    
  156.   addTransitionToLanesMap,
    
  157.   getTransitionsForLanes,
    
  158.   includesOnlyNonUrgentLanes,
    
  159.   includesSomeLane,
    
  160.   OffscreenLane,
    
  161.   SyncUpdateLanes,
    
  162.   UpdateLanes,
    
  163. } from './ReactFiberLane';
    
  164. import {
    
  165.   DiscreteEventPriority,
    
  166.   DefaultEventPriority,
    
  167.   getCurrentUpdatePriority,
    
  168.   setCurrentUpdatePriority,
    
  169.   lowerEventPriority,
    
  170.   lanesToEventPriority,
    
  171. } from './ReactEventPriorities';
    
  172. import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
    
  173. import {
    
  174.   SelectiveHydrationException,
    
  175.   beginWork as originalBeginWork,
    
  176.   replayFunctionComponent,
    
  177. } from './ReactFiberBeginWork';
    
  178. import {completeWork} from './ReactFiberCompleteWork';
    
  179. import {unwindWork, unwindInterruptedWork} from './ReactFiberUnwindWork';
    
  180. import {
    
  181.   throwException,
    
  182.   createRootErrorUpdate,
    
  183.   createClassErrorUpdate,
    
  184. } from './ReactFiberThrow';
    
  185. import {
    
  186.   commitBeforeMutationEffects,
    
  187.   commitLayoutEffects,
    
  188.   commitMutationEffects,
    
  189.   commitPassiveEffectDurations,
    
  190.   commitPassiveMountEffects,
    
  191.   commitPassiveUnmountEffects,
    
  192.   disappearLayoutEffects,
    
  193.   reconnectPassiveEffects,
    
  194.   reappearLayoutEffects,
    
  195.   disconnectPassiveEffect,
    
  196.   reportUncaughtErrorInDEV,
    
  197.   invokeLayoutEffectMountInDEV,
    
  198.   invokePassiveEffectMountInDEV,
    
  199.   invokeLayoutEffectUnmountInDEV,
    
  200.   invokePassiveEffectUnmountInDEV,
    
  201.   accumulateSuspenseyCommit,
    
  202. } from './ReactFiberCommitWork';
    
  203. import {enqueueUpdate} from './ReactFiberClassUpdateQueue';
    
  204. import {resetContextDependencies} from './ReactFiberNewContext';
    
  205. import {
    
  206.   resetHooksAfterThrow,
    
  207.   resetHooksOnUnwind,
    
  208.   ContextOnlyDispatcher,
    
  209. } from './ReactFiberHooks';
    
  210. import {DefaultCacheDispatcher} from './ReactFiberCache';
    
  211. import {
    
  212.   createCapturedValueAtFiber,
    
  213.   type CapturedValue,
    
  214. } from './ReactCapturedValue';
    
  215. import {
    
  216.   enqueueConcurrentRenderForLane,
    
  217.   finishQueueingConcurrentUpdates,
    
  218.   getConcurrentlyUpdatedLanes,
    
  219. } from './ReactFiberConcurrentUpdates';
    
  220. 
    
  221. import {
    
  222.   markNestedUpdateScheduled,
    
  223.   recordCommitTime,
    
  224.   resetNestedUpdateFlag,
    
  225.   startProfilerTimer,
    
  226.   stopProfilerTimerIfRunningAndRecordDelta,
    
  227.   syncNestedUpdateFlag,
    
  228. } from './ReactProfilerTimer';
    
  229. 
    
  230. // DEV stuff
    
  231. import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
    
  232. import ReactStrictModeWarnings from './ReactStrictModeWarnings';
    
  233. import {
    
  234.   isRendering as ReactCurrentDebugFiberIsRenderingInDEV,
    
  235.   current as ReactCurrentFiberCurrent,
    
  236.   resetCurrentFiber as resetCurrentDebugFiberInDEV,
    
  237.   setCurrentFiber as setCurrentDebugFiberInDEV,
    
  238. } from './ReactCurrentFiber';
    
  239. import {
    
  240.   invokeGuardedCallback,
    
  241.   hasCaughtError,
    
  242.   clearCaughtError,
    
  243. } from 'shared/ReactErrorUtils';
    
  244. import {
    
  245.   isDevToolsPresent,
    
  246.   markCommitStarted,
    
  247.   markCommitStopped,
    
  248.   markComponentRenderStopped,
    
  249.   markComponentSuspended,
    
  250.   markComponentErrored,
    
  251.   markLayoutEffectsStarted,
    
  252.   markLayoutEffectsStopped,
    
  253.   markPassiveEffectsStarted,
    
  254.   markPassiveEffectsStopped,
    
  255.   markRenderStarted,
    
  256.   markRenderYielded,
    
  257.   markRenderStopped,
    
  258.   onCommitRoot as onCommitRootDevTools,
    
  259.   onPostCommitRoot as onPostCommitRootDevTools,
    
  260. } from './ReactFiberDevToolsHook';
    
  261. import {onCommitRoot as onCommitRootTestSelector} from './ReactTestSelectors';
    
  262. import {releaseCache} from './ReactFiberCacheComponent';
    
  263. import {
    
  264.   isLegacyActEnvironment,
    
  265.   isConcurrentActEnvironment,
    
  266. } from './ReactFiberAct';
    
  267. import {processTransitionCallbacks} from './ReactFiberTracingMarkerComponent';
    
  268. import {
    
  269.   SuspenseException,
    
  270.   SuspenseyCommitException,
    
  271.   getSuspendedThenable,
    
  272.   isThenableResolved,
    
  273. } from './ReactFiberThenable';
    
  274. import {schedulePostPaintCallback} from './ReactPostPaintCallback';
    
  275. import {
    
  276.   getSuspenseHandler,
    
  277.   getShellBoundary,
    
  278. } from './ReactFiberSuspenseContext';
    
  279. import {resolveDefaultProps} from './ReactFiberLazyComponent';
    
  280. import {resetChildReconcilerOnUnwind} from './ReactChildFiber';
    
  281. import {
    
  282.   ensureRootIsScheduled,
    
  283.   flushSyncWorkOnAllRoots,
    
  284.   flushSyncWorkOnLegacyRootsOnly,
    
  285.   getContinuationForRoot,
    
  286.   requestTransitionLane,
    
  287. } from './ReactFiberRootScheduler';
    
  288. import {getMaskedContext, getUnmaskedContext} from './ReactFiberContext';
    
  289. import {peekEntangledActionLane} from './ReactFiberAsyncAction';
    
  290. 
    
  291. const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
    
  292. 
    
  293. const {
    
  294.   ReactCurrentDispatcher,
    
  295.   ReactCurrentCache,
    
  296.   ReactCurrentOwner,
    
  297.   ReactCurrentBatchConfig,
    
  298.   ReactCurrentActQueue,
    
  299. } = ReactSharedInternals;
    
  300. 
    
  301. type ExecutionContext = number;
    
  302. 
    
  303. export const NoContext = /*             */ 0b000;
    
  304. const BatchedContext = /*               */ 0b001;
    
  305. export const RenderContext = /*         */ 0b010;
    
  306. export const CommitContext = /*         */ 0b100;
    
  307. 
    
  308. type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6;
    
  309. const RootInProgress = 0;
    
  310. const RootFatalErrored = 1;
    
  311. const RootErrored = 2;
    
  312. const RootSuspended = 3;
    
  313. const RootSuspendedWithDelay = 4;
    
  314. const RootCompleted = 5;
    
  315. const RootDidNotComplete = 6;
    
  316. 
    
  317. // Describes where we are in the React execution stack
    
  318. let executionContext: ExecutionContext = NoContext;
    
  319. // The root we're working on
    
  320. let workInProgressRoot: FiberRoot | null = null;
    
  321. // The fiber we're working on
    
  322. let workInProgress: Fiber | null = null;
    
  323. // The lanes we're rendering
    
  324. let workInProgressRootRenderLanes: Lanes = NoLanes;
    
  325. 
    
  326. opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
    
  327. const NotSuspended: SuspendedReason = 0;
    
  328. const SuspendedOnError: SuspendedReason = 1;
    
  329. const SuspendedOnData: SuspendedReason = 2;
    
  330. const SuspendedOnImmediate: SuspendedReason = 3;
    
  331. const SuspendedOnInstance: SuspendedReason = 4;
    
  332. const SuspendedOnInstanceAndReadyToContinue: SuspendedReason = 5;
    
  333. const SuspendedOnDeprecatedThrowPromise: SuspendedReason = 6;
    
  334. const SuspendedAndReadyToContinue: SuspendedReason = 7;
    
  335. const SuspendedOnHydration: SuspendedReason = 8;
    
  336. 
    
  337. // When this is true, the work-in-progress fiber just suspended (or errored) and
    
  338. // we've yet to unwind the stack. In some cases, we may yield to the main thread
    
  339. // after this happens. If the fiber is pinged before we resume, we can retry
    
  340. // immediately instead of unwinding the stack.
    
  341. let workInProgressSuspendedReason: SuspendedReason = NotSuspended;
    
  342. let workInProgressThrownValue: mixed = null;
    
  343. 
    
  344. // Whether a ping listener was attached during this render. This is slightly
    
  345. // different that whether something suspended, because we don't add multiple
    
  346. // listeners to a promise we've already seen (per root and lane).
    
  347. let workInProgressRootDidAttachPingListener: boolean = false;
    
  348. 
    
  349. // A contextual version of workInProgressRootRenderLanes. It is a superset of
    
  350. // the lanes that we started working on at the root. When we enter a subtree
    
  351. // that is currently hidden, we add the lanes that would have committed if
    
  352. // the hidden tree hadn't been deferred. This is modified by the
    
  353. // HiddenContext module.
    
  354. //
    
  355. // Most things in the work loop should deal with workInProgressRootRenderLanes.
    
  356. // Most things in begin/complete phases should deal with entangledRenderLanes.
    
  357. export let entangledRenderLanes: Lanes = NoLanes;
    
  358. 
    
  359. // Whether to root completed, errored, suspended, etc.
    
  360. let workInProgressRootExitStatus: RootExitStatus = RootInProgress;
    
  361. // A fatal error, if one is thrown
    
  362. let workInProgressRootFatalError: mixed = null;
    
  363. // The work left over by components that were visited during this render. Only
    
  364. // includes unprocessed updates, not work in bailed out children.
    
  365. let workInProgressRootSkippedLanes: Lanes = NoLanes;
    
  366. // Lanes that were updated (in an interleaved event) during this render.
    
  367. let workInProgressRootInterleavedUpdatedLanes: Lanes = NoLanes;
    
  368. // Lanes that were updated during the render phase (*not* an interleaved event).
    
  369. let workInProgressRootRenderPhaseUpdatedLanes: Lanes = NoLanes;
    
  370. // Lanes that were pinged (in an interleaved event) during this render.
    
  371. let workInProgressRootPingedLanes: Lanes = NoLanes;
    
  372. // If this lane scheduled deferred work, this is the lane of the deferred task.
    
  373. let workInProgressDeferredLane: Lane = NoLane;
    
  374. // Errors that are thrown during the render phase.
    
  375. let workInProgressRootConcurrentErrors: Array<CapturedValue<mixed>> | null =
    
  376.   null;
    
  377. // These are errors that we recovered from without surfacing them to the UI.
    
  378. // We will log them once the tree commits.
    
  379. let workInProgressRootRecoverableErrors: Array<CapturedValue<mixed>> | null =
    
  380.   null;
    
  381. 
    
  382. // The most recent time we either committed a fallback, or when a fallback was
    
  383. // filled in with the resolved UI. This lets us throttle the appearance of new
    
  384. // content as it streams in, to minimize jank.
    
  385. // TODO: Think of a better name for this variable?
    
  386. let globalMostRecentFallbackTime: number = 0;
    
  387. const FALLBACK_THROTTLE_MS: number = 300;
    
  388. 
    
  389. // The absolute time for when we should start giving up on rendering
    
  390. // more and prefer CPU suspense heuristics instead.
    
  391. let workInProgressRootRenderTargetTime: number = Infinity;
    
  392. // How long a render is supposed to take before we start following CPU
    
  393. // suspense heuristics and opt out of rendering more content.
    
  394. const RENDER_TIMEOUT_MS = 500;
    
  395. 
    
  396. let workInProgressTransitions: Array<Transition> | null = null;
    
  397. export function getWorkInProgressTransitions(): null | Array<Transition> {
    
  398.   return workInProgressTransitions;
    
  399. }
    
  400. 
    
  401. let currentPendingTransitionCallbacks: PendingTransitionCallbacks | null = null;
    
  402. let currentEndTime: number | null = null;
    
  403. 
    
  404. export function addTransitionStartCallbackToPendingTransition(
    
  405.   transition: Transition,
    
  406. ) {
    
  407.   if (enableTransitionTracing) {
    
  408.     if (currentPendingTransitionCallbacks === null) {
    
  409.       currentPendingTransitionCallbacks = {
    
  410.         transitionStart: [],
    
  411.         transitionProgress: null,
    
  412.         transitionComplete: null,
    
  413.         markerProgress: null,
    
  414.         markerIncomplete: null,
    
  415.         markerComplete: null,
    
  416.       };
    
  417.     }
    
  418. 
    
  419.     if (currentPendingTransitionCallbacks.transitionStart === null) {
    
  420.       currentPendingTransitionCallbacks.transitionStart =
    
  421.         ([]: Array<Transition>);
    
  422.     }
    
  423. 
    
  424.     currentPendingTransitionCallbacks.transitionStart.push(transition);
    
  425.   }
    
  426. }
    
  427. 
    
  428. export function addMarkerProgressCallbackToPendingTransition(
    
  429.   markerName: string,
    
  430.   transitions: Set<Transition>,
    
  431.   pendingBoundaries: PendingBoundaries,
    
  432. ) {
    
  433.   if (enableTransitionTracing) {
    
  434.     if (currentPendingTransitionCallbacks === null) {
    
  435.       currentPendingTransitionCallbacks = ({
    
  436.         transitionStart: null,
    
  437.         transitionProgress: null,
    
  438.         transitionComplete: null,
    
  439.         markerProgress: new Map(),
    
  440.         markerIncomplete: null,
    
  441.         markerComplete: null,
    
  442.       }: PendingTransitionCallbacks);
    
  443.     }
    
  444. 
    
  445.     if (currentPendingTransitionCallbacks.markerProgress === null) {
    
  446.       currentPendingTransitionCallbacks.markerProgress = new Map();
    
  447.     }
    
  448. 
    
  449.     currentPendingTransitionCallbacks.markerProgress.set(markerName, {
    
  450.       pendingBoundaries,
    
  451.       transitions,
    
  452.     });
    
  453.   }
    
  454. }
    
  455. 
    
  456. export function addMarkerIncompleteCallbackToPendingTransition(
    
  457.   markerName: string,
    
  458.   transitions: Set<Transition>,
    
  459.   aborts: Array<TransitionAbort>,
    
  460. ) {
    
  461.   if (enableTransitionTracing) {
    
  462.     if (currentPendingTransitionCallbacks === null) {
    
  463.       currentPendingTransitionCallbacks = {
    
  464.         transitionStart: null,
    
  465.         transitionProgress: null,
    
  466.         transitionComplete: null,
    
  467.         markerProgress: null,
    
  468.         markerIncomplete: new Map(),
    
  469.         markerComplete: null,
    
  470.       };
    
  471.     }
    
  472. 
    
  473.     if (currentPendingTransitionCallbacks.markerIncomplete === null) {
    
  474.       currentPendingTransitionCallbacks.markerIncomplete = new Map();
    
  475.     }
    
  476. 
    
  477.     currentPendingTransitionCallbacks.markerIncomplete.set(markerName, {
    
  478.       transitions,
    
  479.       aborts,
    
  480.     });
    
  481.   }
    
  482. }
    
  483. 
    
  484. export function addMarkerCompleteCallbackToPendingTransition(
    
  485.   markerName: string,
    
  486.   transitions: Set<Transition>,
    
  487. ) {
    
  488.   if (enableTransitionTracing) {
    
  489.     if (currentPendingTransitionCallbacks === null) {
    
  490.       currentPendingTransitionCallbacks = {
    
  491.         transitionStart: null,
    
  492.         transitionProgress: null,
    
  493.         transitionComplete: null,
    
  494.         markerProgress: null,
    
  495.         markerIncomplete: null,
    
  496.         markerComplete: new Map(),
    
  497.       };
    
  498.     }
    
  499. 
    
  500.     if (currentPendingTransitionCallbacks.markerComplete === null) {
    
  501.       currentPendingTransitionCallbacks.markerComplete = new Map();
    
  502.     }
    
  503. 
    
  504.     currentPendingTransitionCallbacks.markerComplete.set(
    
  505.       markerName,
    
  506.       transitions,
    
  507.     );
    
  508.   }
    
  509. }
    
  510. 
    
  511. export function addTransitionProgressCallbackToPendingTransition(
    
  512.   transition: Transition,
    
  513.   boundaries: PendingBoundaries,
    
  514. ) {
    
  515.   if (enableTransitionTracing) {
    
  516.     if (currentPendingTransitionCallbacks === null) {
    
  517.       currentPendingTransitionCallbacks = {
    
  518.         transitionStart: null,
    
  519.         transitionProgress: new Map(),
    
  520.         transitionComplete: null,
    
  521.         markerProgress: null,
    
  522.         markerIncomplete: null,
    
  523.         markerComplete: null,
    
  524.       };
    
  525.     }
    
  526. 
    
  527.     if (currentPendingTransitionCallbacks.transitionProgress === null) {
    
  528.       currentPendingTransitionCallbacks.transitionProgress = new Map();
    
  529.     }
    
  530. 
    
  531.     currentPendingTransitionCallbacks.transitionProgress.set(
    
  532.       transition,
    
  533.       boundaries,
    
  534.     );
    
  535.   }
    
  536. }
    
  537. 
    
  538. export function addTransitionCompleteCallbackToPendingTransition(
    
  539.   transition: Transition,
    
  540. ) {
    
  541.   if (enableTransitionTracing) {
    
  542.     if (currentPendingTransitionCallbacks === null) {
    
  543.       currentPendingTransitionCallbacks = {
    
  544.         transitionStart: null,
    
  545.         transitionProgress: null,
    
  546.         transitionComplete: [],
    
  547.         markerProgress: null,
    
  548.         markerIncomplete: null,
    
  549.         markerComplete: null,
    
  550.       };
    
  551.     }
    
  552. 
    
  553.     if (currentPendingTransitionCallbacks.transitionComplete === null) {
    
  554.       currentPendingTransitionCallbacks.transitionComplete =
    
  555.         ([]: Array<Transition>);
    
  556.     }
    
  557. 
    
  558.     currentPendingTransitionCallbacks.transitionComplete.push(transition);
    
  559.   }
    
  560. }
    
  561. 
    
  562. function resetRenderTimer() {
    
  563.   workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;
    
  564. }
    
  565. 
    
  566. export function getRenderTargetTime(): number {
    
  567.   return workInProgressRootRenderTargetTime;
    
  568. }
    
  569. 
    
  570. let hasUncaughtError = false;
    
  571. let firstUncaughtError = null;
    
  572. let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;
    
  573. 
    
  574. // Only used when enableProfilerNestedUpdateScheduledHook is true;
    
  575. // to track which root is currently committing layout effects.
    
  576. let rootCommittingMutationOrLayoutEffects: FiberRoot | null = null;
    
  577. 
    
  578. let rootDoesHavePassiveEffects: boolean = false;
    
  579. let rootWithPendingPassiveEffects: FiberRoot | null = null;
    
  580. let pendingPassiveEffectsLanes: Lanes = NoLanes;
    
  581. let pendingPassiveProfilerEffects: Array<Fiber> = [];
    
  582. let pendingPassiveEffectsRemainingLanes: Lanes = NoLanes;
    
  583. let pendingPassiveTransitions: Array<Transition> | null = null;
    
  584. 
    
  585. // Use these to prevent an infinite loop of nested updates
    
  586. const NESTED_UPDATE_LIMIT = 50;
    
  587. let nestedUpdateCount: number = 0;
    
  588. let rootWithNestedUpdates: FiberRoot | null = null;
    
  589. let isFlushingPassiveEffects = false;
    
  590. let didScheduleUpdateDuringPassiveEffects = false;
    
  591. 
    
  592. const NESTED_PASSIVE_UPDATE_LIMIT = 50;
    
  593. let nestedPassiveUpdateCount: number = 0;
    
  594. let rootWithPassiveNestedUpdates: FiberRoot | null = null;
    
  595. 
    
  596. let isRunningInsertionEffect = false;
    
  597. 
    
  598. export function getWorkInProgressRoot(): FiberRoot | null {
    
  599.   return workInProgressRoot;
    
  600. }
    
  601. 
    
  602. export function getWorkInProgressRootRenderLanes(): Lanes {
    
  603.   return workInProgressRootRenderLanes;
    
  604. }
    
  605. 
    
  606. export function isWorkLoopSuspendedOnData(): boolean {
    
  607.   return workInProgressSuspendedReason === SuspendedOnData;
    
  608. }
    
  609. 
    
  610. export function getCurrentTime(): number {
    
  611.   return now();
    
  612. }
    
  613. 
    
  614. export function requestUpdateLane(fiber: Fiber): Lane {
    
  615.   // Special cases
    
  616.   const mode = fiber.mode;
    
  617.   if ((mode & ConcurrentMode) === NoMode) {
    
  618.     return (SyncLane: Lane);
    
  619.   } else if (
    
  620.     (executionContext & RenderContext) !== NoContext &&
    
  621.     workInProgressRootRenderLanes !== NoLanes
    
  622.   ) {
    
  623.     // This is a render phase update. These are not officially supported. The
    
  624.     // old behavior is to give this the same "thread" (lanes) as
    
  625.     // whatever is currently rendering. So if you call `setState` on a component
    
  626.     // that happens later in the same render, it will flush. Ideally, we want to
    
  627.     // remove the special case and treat them as if they came from an
    
  628.     // interleaved event. Regardless, this pattern is not officially supported.
    
  629.     // This behavior is only a fallback. The flag only exists until we can roll
    
  630.     // out the setState warning, since existing code might accidentally rely on
    
  631.     // the current behavior.
    
  632.     return pickArbitraryLane(workInProgressRootRenderLanes);
    
  633.   }
    
  634. 
    
  635.   const isTransition = requestCurrentTransition() !== NoTransition;
    
  636.   if (isTransition) {
    
  637.     if (__DEV__ && ReactCurrentBatchConfig.transition !== null) {
    
  638.       const transition = ReactCurrentBatchConfig.transition;
    
  639.       if (!transition._updatedFibers) {
    
  640.         transition._updatedFibers = new Set();
    
  641.       }
    
  642. 
    
  643.       transition._updatedFibers.add(fiber);
    
  644.     }
    
  645. 
    
  646.     const actionScopeLane = peekEntangledActionLane();
    
  647.     return actionScopeLane !== NoLane
    
  648.       ? // We're inside an async action scope. Reuse the same lane.
    
  649.         actionScopeLane
    
  650.       : // We may or may not be inside an async action scope. If we are, this
    
  651.         // is the first update in that scope. Either way, we need to get a
    
  652.         // fresh transition lane.
    
  653.         requestTransitionLane();
    
  654.   }
    
  655. 
    
  656.   // Updates originating inside certain React methods, like flushSync, have
    
  657.   // their priority set by tracking it with a context variable.
    
  658.   //
    
  659.   // The opaque type returned by the host config is internally a lane, so we can
    
  660.   // use that directly.
    
  661.   // TODO: Move this type conversion to the event priority module.
    
  662.   const updateLane: Lane = (getCurrentUpdatePriority(): any);
    
  663.   if (updateLane !== NoLane) {
    
  664.     return updateLane;
    
  665.   }
    
  666. 
    
  667.   // This update originated outside React. Ask the host environment for an
    
  668.   // appropriate priority, based on the type of event.
    
  669.   //
    
  670.   // The opaque type returned by the host config is internally a lane, so we can
    
  671.   // use that directly.
    
  672.   // TODO: Move this type conversion to the event priority module.
    
  673.   const eventLane: Lane = (getCurrentEventPriority(): any);
    
  674.   return eventLane;
    
  675. }
    
  676. 
    
  677. function requestRetryLane(fiber: Fiber) {
    
  678.   // This is a fork of `requestUpdateLane` designed specifically for Suspense
    
  679.   // "retries" — a special update that attempts to flip a Suspense boundary
    
  680.   // from its placeholder state to its primary/resolved state.
    
  681. 
    
  682.   // Special cases
    
  683.   const mode = fiber.mode;
    
  684.   if ((mode & ConcurrentMode) === NoMode) {
    
  685.     return (SyncLane: Lane);
    
  686.   }
    
  687. 
    
  688.   return claimNextRetryLane();
    
  689. }
    
  690. 
    
  691. export function requestDeferredLane(): Lane {
    
  692.   if (workInProgressDeferredLane === NoLane) {
    
  693.     // If there are multiple useDeferredValue hooks in the same render, the
    
  694.     // tasks that they spawn should all be batched together, so they should all
    
  695.     // receive the same lane.
    
  696. 
    
  697.     // Check the priority of the current render to decide the priority of the
    
  698.     // deferred task.
    
  699. 
    
  700.     // OffscreenLane is used for prerendering, but we also use OffscreenLane
    
  701.     // for incremental hydration. It's given the lowest priority because the
    
  702.     // initial HTML is the same as the final UI. But useDeferredValue during
    
  703.     // hydration is an exception — we need to upgrade the UI to the final
    
  704.     // value. So if we're currently hydrating, we treat it like a transition.
    
  705.     const isPrerendering =
    
  706.       includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) &&
    
  707.       !getIsHydrating();
    
  708.     if (isPrerendering) {
    
  709.       // There's only one OffscreenLane, so if it contains deferred work, we
    
  710.       // should just reschedule using the same lane.
    
  711.       workInProgressDeferredLane = OffscreenLane;
    
  712.     } else {
    
  713.       // Everything else is spawned as a transition.
    
  714.       workInProgressDeferredLane = requestTransitionLane();
    
  715.     }
    
  716.   }
    
  717.   return workInProgressDeferredLane;
    
  718. }
    
  719. 
    
  720. export function scheduleUpdateOnFiber(
    
  721.   root: FiberRoot,
    
  722.   fiber: Fiber,
    
  723.   lane: Lane,
    
  724. ) {
    
  725.   if (__DEV__) {
    
  726.     if (isRunningInsertionEffect) {
    
  727.       console.error('useInsertionEffect must not schedule updates.');
    
  728.     }
    
  729.   }
    
  730. 
    
  731.   if (__DEV__) {
    
  732.     if (isFlushingPassiveEffects) {
    
  733.       didScheduleUpdateDuringPassiveEffects = true;
    
  734.     }
    
  735.   }
    
  736. 
    
  737.   // Check if the work loop is currently suspended and waiting for data to
    
  738.   // finish loading.
    
  739.   if (
    
  740.     // Suspended render phase
    
  741.     (root === workInProgressRoot &&
    
  742.       workInProgressSuspendedReason === SuspendedOnData) ||
    
  743.     // Suspended commit phase
    
  744.     root.cancelPendingCommit !== null
    
  745.   ) {
    
  746.     // The incoming update might unblock the current render. Interrupt the
    
  747.     // current attempt and restart from the top.
    
  748.     prepareFreshStack(root, NoLanes);
    
  749.     markRootSuspended(
    
  750.       root,
    
  751.       workInProgressRootRenderLanes,
    
  752.       workInProgressDeferredLane,
    
  753.     );
    
  754.   }
    
  755. 
    
  756.   // Mark that the root has a pending update.
    
  757.   markRootUpdated(root, lane);
    
  758. 
    
  759.   if (
    
  760.     (executionContext & RenderContext) !== NoLanes &&
    
  761.     root === workInProgressRoot
    
  762.   ) {
    
  763.     // This update was dispatched during the render phase. This is a mistake
    
  764.     // if the update originates from user space (with the exception of local
    
  765.     // hook updates, which are handled differently and don't reach this
    
  766.     // function), but there are some internal React features that use this as
    
  767.     // an implementation detail, like selective hydration.
    
  768.     warnAboutRenderPhaseUpdatesInDEV(fiber);
    
  769. 
    
  770.     // Track lanes that were updated during the render phase
    
  771.     workInProgressRootRenderPhaseUpdatedLanes = mergeLanes(
    
  772.       workInProgressRootRenderPhaseUpdatedLanes,
    
  773.       lane,
    
  774.     );
    
  775.   } else {
    
  776.     // This is a normal update, scheduled from outside the render phase. For
    
  777.     // example, during an input event.
    
  778.     if (enableUpdaterTracking) {
    
  779.       if (isDevToolsPresent) {
    
  780.         addFiberToLanesMap(root, fiber, lane);
    
  781.       }
    
  782.     }
    
  783. 
    
  784.     warnIfUpdatesNotWrappedWithActDEV(fiber);
    
  785. 
    
  786.     if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {
    
  787.       if (
    
  788.         (executionContext & CommitContext) !== NoContext &&
    
  789.         root === rootCommittingMutationOrLayoutEffects
    
  790.       ) {
    
  791.         if (fiber.mode & ProfileMode) {
    
  792.           let current: null | Fiber = fiber;
    
  793.           while (current !== null) {
    
  794.             if (current.tag === Profiler) {
    
  795.               const {id, onNestedUpdateScheduled} = current.memoizedProps;
    
  796.               if (typeof onNestedUpdateScheduled === 'function') {
    
  797.                 onNestedUpdateScheduled(id);
    
  798.               }
    
  799.             }
    
  800.             current = current.return;
    
  801.           }
    
  802.         }
    
  803.       }
    
  804.     }
    
  805. 
    
  806.     if (enableTransitionTracing) {
    
  807.       const transition = ReactCurrentBatchConfig.transition;
    
  808.       if (transition !== null && transition.name != null) {
    
  809.         if (transition.startTime === -1) {
    
  810.           transition.startTime = now();
    
  811.         }
    
  812. 
    
  813.         addTransitionToLanesMap(root, transition, lane);
    
  814.       }
    
  815.     }
    
  816. 
    
  817.     if (root === workInProgressRoot) {
    
  818.       // Received an update to a tree that's in the middle of rendering. Mark
    
  819.       // that there was an interleaved update work on this root.
    
  820.       if ((executionContext & RenderContext) === NoContext) {
    
  821.         workInProgressRootInterleavedUpdatedLanes = mergeLanes(
    
  822.           workInProgressRootInterleavedUpdatedLanes,
    
  823.           lane,
    
  824.         );
    
  825.       }
    
  826.       if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
    
  827.         // The root already suspended with a delay, which means this render
    
  828.         // definitely won't finish. Since we have a new update, let's mark it as
    
  829.         // suspended now, right before marking the incoming update. This has the
    
  830.         // effect of interrupting the current render and switching to the update.
    
  831.         // TODO: Make sure this doesn't override pings that happen while we've
    
  832.         // already started rendering.
    
  833.         markRootSuspended(
    
  834.           root,
    
  835.           workInProgressRootRenderLanes,
    
  836.           workInProgressDeferredLane,
    
  837.         );
    
  838.       }
    
  839.     }
    
  840. 
    
  841.     ensureRootIsScheduled(root);
    
  842.     if (
    
  843.       lane === SyncLane &&
    
  844.       executionContext === NoContext &&
    
  845.       (fiber.mode & ConcurrentMode) === NoMode
    
  846.     ) {
    
  847.       if (__DEV__ && ReactCurrentActQueue.isBatchingLegacy) {
    
  848.         // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode.
    
  849.       } else {
    
  850.         // Flush the synchronous work now, unless we're already working or inside
    
  851.         // a batch. This is intentionally inside scheduleUpdateOnFiber instead of
    
  852.         // scheduleCallbackForFiber to preserve the ability to schedule a callback
    
  853.         // without immediately flushing it. We only do this for user-initiated
    
  854.         // updates, to preserve historical behavior of legacy mode.
    
  855.         resetRenderTimer();
    
  856.         flushSyncWorkOnLegacyRootsOnly();
    
  857.       }
    
  858.     }
    
  859.   }
    
  860. }
    
  861. 
    
  862. export function scheduleInitialHydrationOnRoot(root: FiberRoot, lane: Lane) {
    
  863.   // This is a special fork of scheduleUpdateOnFiber that is only used to
    
  864.   // schedule the initial hydration of a root that has just been created. Most
    
  865.   // of the stuff in scheduleUpdateOnFiber can be skipped.
    
  866.   //
    
  867.   // The main reason for this separate path, though, is to distinguish the
    
  868.   // initial children from subsequent updates. In fully client-rendered roots
    
  869.   // (createRoot instead of hydrateRoot), all top-level renders are modeled as
    
  870.   // updates, but hydration roots are special because the initial render must
    
  871.   // match what was rendered on the server.
    
  872.   const current = root.current;
    
  873.   current.lanes = lane;
    
  874.   markRootUpdated(root, lane);
    
  875.   ensureRootIsScheduled(root);
    
  876. }
    
  877. 
    
  878. export function isUnsafeClassRenderPhaseUpdate(fiber: Fiber): boolean {
    
  879.   // Check if this is a render phase update. Only called by class components,
    
  880.   // which special (deprecated) behavior for UNSAFE_componentWillReceive props.
    
  881.   return (executionContext & RenderContext) !== NoContext;
    
  882. }
    
  883. 
    
  884. // This is the entry point for every concurrent task, i.e. anything that
    
  885. // goes through Scheduler.
    
  886. export function performConcurrentWorkOnRoot(
    
  887.   root: FiberRoot,
    
  888.   didTimeout: boolean,
    
  889. ): RenderTaskFn | null {
    
  890.   if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
    
  891.     resetNestedUpdateFlag();
    
  892.   }
    
  893. 
    
  894.   if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
    
  895.     throw new Error('Should not already be working.');
    
  896.   }
    
  897. 
    
  898.   // Flush any pending passive effects before deciding which lanes to work on,
    
  899.   // in case they schedule additional work.
    
  900.   const originalCallbackNode = root.callbackNode;
    
  901.   const didFlushPassiveEffects = flushPassiveEffects();
    
  902.   if (didFlushPassiveEffects) {
    
  903.     // Something in the passive effect phase may have canceled the current task.
    
  904.     // Check if the task node for this root was changed.
    
  905.     if (root.callbackNode !== originalCallbackNode) {
    
  906.       // The current task was canceled. Exit. We don't need to call
    
  907.       // `ensureRootIsScheduled` because the check above implies either that
    
  908.       // there's a new task, or that there's no remaining work on this root.
    
  909.       return null;
    
  910.     } else {
    
  911.       // Current task was not canceled. Continue.
    
  912.     }
    
  913.   }
    
  914. 
    
  915.   // Determine the next lanes to work on, using the fields stored
    
  916.   // on the root.
    
  917.   // TODO: This was already computed in the caller. Pass it as an argument.
    
  918.   let lanes = getNextLanes(
    
  919.     root,
    
  920.     root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
    
  921.   );
    
  922.   if (lanes === NoLanes) {
    
  923.     // Defensive coding. This is never expected to happen.
    
  924.     return null;
    
  925.   }
    
  926. 
    
  927.   // We disable time-slicing in some cases: if the work has been CPU-bound
    
  928.   // for too long ("expired" work, to prevent starvation), or we're in
    
  929.   // sync-updates-by-default mode.
    
  930.   // TODO: We only check `didTimeout` defensively, to account for a Scheduler
    
  931.   // bug we're still investigating. Once the bug in Scheduler is fixed,
    
  932.   // we can remove this, since we track expiration ourselves.
    
  933.   const shouldTimeSlice =
    
  934.     !includesBlockingLane(root, lanes) &&
    
  935.     !includesExpiredLane(root, lanes) &&
    
  936.     (disableSchedulerTimeoutInWorkLoop || !didTimeout);
    
  937.   let exitStatus = shouldTimeSlice
    
  938.     ? renderRootConcurrent(root, lanes)
    
  939.     : renderRootSync(root, lanes);
    
  940. 
    
  941.   if (exitStatus !== RootInProgress) {
    
  942.     let renderWasConcurrent = shouldTimeSlice;
    
  943.     do {
    
  944.       if (exitStatus === RootDidNotComplete) {
    
  945.         // The render unwound without completing the tree. This happens in special
    
  946.         // cases where need to exit the current render without producing a
    
  947.         // consistent tree or committing.
    
  948.         markRootSuspended(root, lanes, NoLane);
    
  949.       } else {
    
  950.         // The render completed.
    
  951. 
    
  952.         // Check if this render may have yielded to a concurrent event, and if so,
    
  953.         // confirm that any newly rendered stores are consistent.
    
  954.         // TODO: It's possible that even a concurrent render may never have yielded
    
  955.         // to the main thread, if it was fast enough, or if it expired. We could
    
  956.         // skip the consistency check in that case, too.
    
  957.         const finishedWork: Fiber = (root.current.alternate: any);
    
  958.         if (
    
  959.           renderWasConcurrent &&
    
  960.           !isRenderConsistentWithExternalStores(finishedWork)
    
  961.         ) {
    
  962.           // A store was mutated in an interleaved event. Render again,
    
  963.           // synchronously, to block further mutations.
    
  964.           exitStatus = renderRootSync(root, lanes);
    
  965.           // We assume the tree is now consistent because we didn't yield to any
    
  966.           // concurrent events.
    
  967.           renderWasConcurrent = false;
    
  968.           // Need to check the exit status again.
    
  969.           continue;
    
  970.         }
    
  971. 
    
  972.         // Check if something threw
    
  973.         if (exitStatus === RootErrored) {
    
  974.           const originallyAttemptedLanes = lanes;
    
  975.           const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
    
  976.             root,
    
  977.             originallyAttemptedLanes,
    
  978.           );
    
  979.           if (errorRetryLanes !== NoLanes) {
    
  980.             lanes = errorRetryLanes;
    
  981.             exitStatus = recoverFromConcurrentError(
    
  982.               root,
    
  983.               originallyAttemptedLanes,
    
  984.               errorRetryLanes,
    
  985.             );
    
  986.             renderWasConcurrent = false;
    
  987.           }
    
  988.         }
    
  989.         if (exitStatus === RootFatalErrored) {
    
  990.           const fatalError = workInProgressRootFatalError;
    
  991.           prepareFreshStack(root, NoLanes);
    
  992.           markRootSuspended(root, lanes, NoLane);
    
  993.           ensureRootIsScheduled(root);
    
  994.           throw fatalError;
    
  995.         }
    
  996. 
    
  997.         // We now have a consistent tree. The next step is either to commit it,
    
  998.         // or, if something suspended, wait to commit it after a timeout.
    
  999.         root.finishedWork = finishedWork;
    
  1000.         root.finishedLanes = lanes;
    
  1001.         finishConcurrentRender(root, exitStatus, finishedWork, lanes);
    
  1002.       }
    
  1003.       break;
    
  1004.     } while (true);
    
  1005.   }
    
  1006. 
    
  1007.   ensureRootIsScheduled(root);
    
  1008.   return getContinuationForRoot(root, originalCallbackNode);
    
  1009. }
    
  1010. 
    
  1011. function recoverFromConcurrentError(
    
  1012.   root: FiberRoot,
    
  1013.   originallyAttemptedLanes: Lanes,
    
  1014.   errorRetryLanes: Lanes,
    
  1015. ) {
    
  1016.   // If an error occurred during hydration, discard server response and fall
    
  1017.   // back to client side render.
    
  1018. 
    
  1019.   // Before rendering again, save the errors from the previous attempt.
    
  1020.   const errorsFromFirstAttempt = workInProgressRootConcurrentErrors;
    
  1021. 
    
  1022.   const wasRootDehydrated = isRootDehydrated(root);
    
  1023.   if (wasRootDehydrated) {
    
  1024.     // The shell failed to hydrate. Set a flag to force a client rendering
    
  1025.     // during the next attempt. To do this, we call prepareFreshStack now
    
  1026.     // to create the root work-in-progress fiber. This is a bit weird in terms
    
  1027.     // of factoring, because it relies on renderRootSync not calling
    
  1028.     // prepareFreshStack again in the call below, which happens because the
    
  1029.     // root and lanes haven't changed.
    
  1030.     //
    
  1031.     // TODO: I think what we should do is set ForceClientRender inside
    
  1032.     // throwException, like we do for nested Suspense boundaries. The reason
    
  1033.     // it's here instead is so we can switch to the synchronous work loop, too.
    
  1034.     // Something to consider for a future refactor.
    
  1035.     const rootWorkInProgress = prepareFreshStack(root, errorRetryLanes);
    
  1036.     rootWorkInProgress.flags |= ForceClientRender;
    
  1037.     if (__DEV__) {
    
  1038.       errorHydratingContainer(root.containerInfo);
    
  1039.     }
    
  1040.   }
    
  1041. 
    
  1042.   const exitStatus = renderRootSync(root, errorRetryLanes);
    
  1043.   if (exitStatus !== RootErrored) {
    
  1044.     // Successfully finished rendering on retry
    
  1045. 
    
  1046.     if (workInProgressRootDidAttachPingListener && !wasRootDehydrated) {
    
  1047.       // During the synchronous render, we attached additional ping listeners.
    
  1048.       // This is highly suggestive of an uncached promise (though it's not the
    
  1049.       // only reason this would happen). If it was an uncached promise, then
    
  1050.       // it may have masked a downstream error from ocurring without actually
    
  1051.       // fixing it. Example:
    
  1052.       //
    
  1053.       //    use(Promise.resolve('uncached'))
    
  1054.       //    throw new Error('Oops!')
    
  1055.       //
    
  1056.       // When this happens, there's a conflict between blocking potential
    
  1057.       // concurrent data races and unwrapping uncached promise values. We
    
  1058.       // have to choose one or the other. Because the data race recovery is
    
  1059.       // a last ditch effort, we'll disable it.
    
  1060.       root.errorRecoveryDisabledLanes = mergeLanes(
    
  1061.         root.errorRecoveryDisabledLanes,
    
  1062.         originallyAttemptedLanes,
    
  1063.       );
    
  1064. 
    
  1065.       // Mark the current render as suspended and force it to restart. Once
    
  1066.       // these lanes finish successfully, we'll re-enable the error recovery
    
  1067.       // mechanism for subsequent updates.
    
  1068.       workInProgressRootInterleavedUpdatedLanes |= originallyAttemptedLanes;
    
  1069.       return RootSuspendedWithDelay;
    
  1070.     }
    
  1071. 
    
  1072.     // The errors from the failed first attempt have been recovered. Add
    
  1073.     // them to the collection of recoverable errors. We'll log them in the
    
  1074.     // commit phase.
    
  1075.     const errorsFromSecondAttempt = workInProgressRootRecoverableErrors;
    
  1076.     workInProgressRootRecoverableErrors = errorsFromFirstAttempt;
    
  1077.     // The errors from the second attempt should be queued after the errors
    
  1078.     // from the first attempt, to preserve the causal sequence.
    
  1079.     if (errorsFromSecondAttempt !== null) {
    
  1080.       queueRecoverableErrors(errorsFromSecondAttempt);
    
  1081.     }
    
  1082.   } else {
    
  1083.     // The UI failed to recover.
    
  1084.   }
    
  1085.   return exitStatus;
    
  1086. }
    
  1087. 
    
  1088. export function queueRecoverableErrors(errors: Array<CapturedValue<mixed>>) {
    
  1089.   if (workInProgressRootRecoverableErrors === null) {
    
  1090.     workInProgressRootRecoverableErrors = errors;
    
  1091.   } else {
    
  1092.     // $FlowFixMe[method-unbinding]
    
  1093.     workInProgressRootRecoverableErrors.push.apply(
    
  1094.       workInProgressRootRecoverableErrors,
    
  1095.       errors,
    
  1096.     );
    
  1097.   }
    
  1098. }
    
  1099. 
    
  1100. function finishConcurrentRender(
    
  1101.   root: FiberRoot,
    
  1102.   exitStatus: RootExitStatus,
    
  1103.   finishedWork: Fiber,
    
  1104.   lanes: Lanes,
    
  1105. ) {
    
  1106.   // TODO: The fact that most of these branches are identical suggests that some
    
  1107.   // of the exit statuses are not best modeled as exit statuses and should be
    
  1108.   // tracked orthogonally.
    
  1109.   switch (exitStatus) {
    
  1110.     case RootInProgress:
    
  1111.     case RootFatalErrored: {
    
  1112.       throw new Error('Root did not complete. This is a bug in React.');
    
  1113.     }
    
  1114.     case RootSuspendedWithDelay: {
    
  1115.       if (includesOnlyTransitions(lanes)) {
    
  1116.         // This is a transition, so we should exit without committing a
    
  1117.         // placeholder and without scheduling a timeout. Delay indefinitely
    
  1118.         // until we receive more data.
    
  1119.         markRootSuspended(root, lanes, workInProgressDeferredLane);
    
  1120.         return;
    
  1121.       }
    
  1122.       // Commit the placeholder.
    
  1123.       break;
    
  1124.     }
    
  1125.     case RootErrored:
    
  1126.     case RootSuspended:
    
  1127.     case RootCompleted: {
    
  1128.       break;
    
  1129.     }
    
  1130.     default: {
    
  1131.       throw new Error('Unknown root exit status.');
    
  1132.     }
    
  1133.   }
    
  1134. 
    
  1135.   if (shouldForceFlushFallbacksInDEV()) {
    
  1136.     // We're inside an `act` scope. Commit immediately.
    
  1137.     commitRoot(
    
  1138.       root,
    
  1139.       workInProgressRootRecoverableErrors,
    
  1140.       workInProgressTransitions,
    
  1141.       workInProgressDeferredLane,
    
  1142.     );
    
  1143.   } else {
    
  1144.     if (
    
  1145.       includesOnlyRetries(lanes) &&
    
  1146.       (alwaysThrottleRetries || exitStatus === RootSuspended)
    
  1147.     ) {
    
  1148.       // This render only included retries, no updates. Throttle committing
    
  1149.       // retries so that we don't show too many loading states too quickly.
    
  1150.       const msUntilTimeout =
    
  1151.         globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();
    
  1152. 
    
  1153.       // Don't bother with a very short suspense time.
    
  1154.       if (msUntilTimeout > 10) {
    
  1155.         markRootSuspended(root, lanes, workInProgressDeferredLane);
    
  1156. 
    
  1157.         const nextLanes = getNextLanes(root, NoLanes);
    
  1158.         if (nextLanes !== NoLanes) {
    
  1159.           // There's additional work we can do on this root. We might as well
    
  1160.           // attempt to work on that while we're suspended.
    
  1161.           return;
    
  1162.         }
    
  1163. 
    
  1164.         // The render is suspended, it hasn't timed out, and there's no
    
  1165.         // lower priority work to do. Instead of committing the fallback
    
  1166.         // immediately, wait for more data to arrive.
    
  1167.         // TODO: Combine retry throttling with Suspensey commits. Right now they
    
  1168.         // run one after the other.
    
  1169.         root.timeoutHandle = scheduleTimeout(
    
  1170.           commitRootWhenReady.bind(
    
  1171.             null,
    
  1172.             root,
    
  1173.             finishedWork,
    
  1174.             workInProgressRootRecoverableErrors,
    
  1175.             workInProgressTransitions,
    
  1176.             lanes,
    
  1177.             workInProgressDeferredLane,
    
  1178.           ),
    
  1179.           msUntilTimeout,
    
  1180.         );
    
  1181.         return;
    
  1182.       }
    
  1183.     }
    
  1184.     commitRootWhenReady(
    
  1185.       root,
    
  1186.       finishedWork,
    
  1187.       workInProgressRootRecoverableErrors,
    
  1188.       workInProgressTransitions,
    
  1189.       lanes,
    
  1190.       workInProgressDeferredLane,
    
  1191.     );
    
  1192.   }
    
  1193. }
    
  1194. 
    
  1195. function commitRootWhenReady(
    
  1196.   root: FiberRoot,
    
  1197.   finishedWork: Fiber,
    
  1198.   recoverableErrors: Array<CapturedValue<mixed>> | null,
    
  1199.   transitions: Array<Transition> | null,
    
  1200.   lanes: Lanes,
    
  1201.   spawnedLane: Lane,
    
  1202. ) {
    
  1203.   // TODO: Combine retry throttling with Suspensey commits. Right now they run
    
  1204.   // one after the other.
    
  1205.   if (includesOnlyNonUrgentLanes(lanes)) {
    
  1206.     // Before committing, ask the renderer whether the host tree is ready.
    
  1207.     // If it's not, we'll wait until it notifies us.
    
  1208.     startSuspendingCommit();
    
  1209.     // This will walk the completed fiber tree and attach listeners to all
    
  1210.     // the suspensey resources. The renderer is responsible for accumulating
    
  1211.     // all the load events. This all happens in a single synchronous
    
  1212.     // transaction, so it track state in its own module scope.
    
  1213.     accumulateSuspenseyCommit(finishedWork);
    
  1214.     // At the end, ask the renderer if it's ready to commit, or if we should
    
  1215.     // suspend. If it's not ready, it will return a callback to subscribe to
    
  1216.     // a ready event.
    
  1217.     const schedulePendingCommit = waitForCommitToBeReady();
    
  1218.     if (schedulePendingCommit !== null) {
    
  1219.       // NOTE: waitForCommitToBeReady returns a subscribe function so that we
    
  1220.       // only allocate a function if the commit isn't ready yet. The other
    
  1221.       // pattern would be to always pass a callback to waitForCommitToBeReady.
    
  1222. 
    
  1223.       // Not yet ready to commit. Delay the commit until the renderer notifies
    
  1224.       // us that it's ready. This will be canceled if we start work on the
    
  1225.       // root again.
    
  1226.       root.cancelPendingCommit = schedulePendingCommit(
    
  1227.         commitRoot.bind(null, root, recoverableErrors, transitions),
    
  1228.       );
    
  1229.       markRootSuspended(root, lanes, spawnedLane);
    
  1230.       return;
    
  1231.     }
    
  1232.   }
    
  1233. 
    
  1234.   // Otherwise, commit immediately.
    
  1235.   commitRoot(root, recoverableErrors, transitions, spawnedLane);
    
  1236. }
    
  1237. 
    
  1238. function isRenderConsistentWithExternalStores(finishedWork: Fiber): boolean {
    
  1239.   // Search the rendered tree for external store reads, and check whether the
    
  1240.   // stores were mutated in a concurrent event. Intentionally using an iterative
    
  1241.   // loop instead of recursion so we can exit early.
    
  1242.   let node: Fiber = finishedWork;
    
  1243.   while (true) {
    
  1244.     if (node.flags & StoreConsistency) {
    
  1245.       const updateQueue: FunctionComponentUpdateQueue | null =
    
  1246.         (node.updateQueue: any);
    
  1247.       if (updateQueue !== null) {
    
  1248.         const checks = updateQueue.stores;
    
  1249.         if (checks !== null) {
    
  1250.           for (let i = 0; i < checks.length; i++) {
    
  1251.             const check = checks[i];
    
  1252.             const getSnapshot = check.getSnapshot;
    
  1253.             const renderedValue = check.value;
    
  1254.             try {
    
  1255.               if (!is(getSnapshot(), renderedValue)) {
    
  1256.                 // Found an inconsistent store.
    
  1257.                 return false;
    
  1258.               }
    
  1259.             } catch (error) {
    
  1260.               // If `getSnapshot` throws, return `false`. This will schedule
    
  1261.               // a re-render, and the error will be rethrown during render.
    
  1262.               return false;
    
  1263.             }
    
  1264.           }
    
  1265.         }
    
  1266.       }
    
  1267.     }
    
  1268.     const child = node.child;
    
  1269.     if (node.subtreeFlags & StoreConsistency && child !== null) {
    
  1270.       child.return = node;
    
  1271.       node = child;
    
  1272.       continue;
    
  1273.     }
    
  1274.     if (node === finishedWork) {
    
  1275.       return true;
    
  1276.     }
    
  1277.     while (node.sibling === null) {
    
  1278.       if (node.return === null || node.return === finishedWork) {
    
  1279.         return true;
    
  1280.       }
    
  1281.       node = node.return;
    
  1282.     }
    
  1283.     node.sibling.return = node.return;
    
  1284.     node = node.sibling;
    
  1285.   }
    
  1286.   // Flow doesn't know this is unreachable, but eslint does
    
  1287.   // eslint-disable-next-line no-unreachable
    
  1288.   return true;
    
  1289. }
    
  1290. 
    
  1291. function markRootSuspended(
    
  1292.   root: FiberRoot,
    
  1293.   suspendedLanes: Lanes,
    
  1294.   spawnedLane: Lane,
    
  1295. ) {
    
  1296.   // When suspending, we should always exclude lanes that were pinged or (more
    
  1297.   // rarely, since we try to avoid it) updated during the render phase.
    
  1298.   // TODO: Lol maybe there's a better way to factor this besides this
    
  1299.   // obnoxiously named function :)
    
  1300.   suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);
    
  1301.   suspendedLanes = removeLanes(
    
  1302.     suspendedLanes,
    
  1303.     workInProgressRootInterleavedUpdatedLanes,
    
  1304.   );
    
  1305.   markRootSuspended_dontCallThisOneDirectly(root, suspendedLanes, spawnedLane);
    
  1306. }
    
  1307. 
    
  1308. // This is the entry point for synchronous tasks that don't go
    
  1309. // through Scheduler
    
  1310. export function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes): null {
    
  1311.   if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
    
  1312.     throw new Error('Should not already be working.');
    
  1313.   }
    
  1314. 
    
  1315.   const didFlushPassiveEffects = flushPassiveEffects();
    
  1316.   if (didFlushPassiveEffects) {
    
  1317.     // If passive effects were flushed, exit to the outer work loop in the root
    
  1318.     // scheduler, so we can recompute the priority.
    
  1319.     // TODO: We don't actually need this `ensureRootIsScheduled` call because
    
  1320.     // this path is only reachable if the root is already part of the schedule.
    
  1321.     // I'm including it only for consistency with the other exit points from
    
  1322.     // this function. Can address in a subsequent refactor.
    
  1323.     ensureRootIsScheduled(root);
    
  1324.     return null;
    
  1325.   }
    
  1326. 
    
  1327.   if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
    
  1328.     syncNestedUpdateFlag();
    
  1329.   }
    
  1330. 
    
  1331.   let exitStatus = renderRootSync(root, lanes);
    
  1332.   if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
    
  1333.     // If something threw an error, try rendering one more time. We'll render
    
  1334.     // synchronously to block concurrent data mutations, and we'll includes
    
  1335.     // all pending updates are included. If it still fails after the second
    
  1336.     // attempt, we'll give up and commit the resulting tree.
    
  1337.     const originallyAttemptedLanes = lanes;
    
  1338.     const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
    
  1339.       root,
    
  1340.       originallyAttemptedLanes,
    
  1341.     );
    
  1342.     if (errorRetryLanes !== NoLanes) {
    
  1343.       lanes = errorRetryLanes;
    
  1344.       exitStatus = recoverFromConcurrentError(
    
  1345.         root,
    
  1346.         originallyAttemptedLanes,
    
  1347.         errorRetryLanes,
    
  1348.       );
    
  1349.     }
    
  1350.   }
    
  1351. 
    
  1352.   if (exitStatus === RootFatalErrored) {
    
  1353.     const fatalError = workInProgressRootFatalError;
    
  1354.     prepareFreshStack(root, NoLanes);
    
  1355.     markRootSuspended(root, lanes, NoLane);
    
  1356.     ensureRootIsScheduled(root);
    
  1357.     throw fatalError;
    
  1358.   }
    
  1359. 
    
  1360.   if (exitStatus === RootDidNotComplete) {
    
  1361.     // The render unwound without completing the tree. This happens in special
    
  1362.     // cases where need to exit the current render without producing a
    
  1363.     // consistent tree or committing.
    
  1364.     markRootSuspended(root, lanes, NoLane);
    
  1365.     ensureRootIsScheduled(root);
    
  1366.     return null;
    
  1367.   }
    
  1368. 
    
  1369.   // We now have a consistent tree. Because this is a sync render, we
    
  1370.   // will commit it even if something suspended.
    
  1371.   const finishedWork: Fiber = (root.current.alternate: any);
    
  1372.   root.finishedWork = finishedWork;
    
  1373.   root.finishedLanes = lanes;
    
  1374.   commitRoot(
    
  1375.     root,
    
  1376.     workInProgressRootRecoverableErrors,
    
  1377.     workInProgressTransitions,
    
  1378.     workInProgressDeferredLane,
    
  1379.   );
    
  1380. 
    
  1381.   // Before exiting, make sure there's a callback scheduled for the next
    
  1382.   // pending level.
    
  1383.   ensureRootIsScheduled(root);
    
  1384. 
    
  1385.   return null;
    
  1386. }
    
  1387. 
    
  1388. export function flushRoot(root: FiberRoot, lanes: Lanes) {
    
  1389.   if (lanes !== NoLanes) {
    
  1390.     upgradePendingLanesToSync(root, lanes);
    
  1391.     ensureRootIsScheduled(root);
    
  1392.     if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
    
  1393.       resetRenderTimer();
    
  1394.       // TODO: For historical reasons this flushes all sync work across all
    
  1395.       // roots. It shouldn't really matter either way, but we could change this
    
  1396.       // to only flush the given root.
    
  1397.       flushSyncWorkOnAllRoots();
    
  1398.     }
    
  1399.   }
    
  1400. }
    
  1401. 
    
  1402. export function getExecutionContext(): ExecutionContext {
    
  1403.   return executionContext;
    
  1404. }
    
  1405. 
    
  1406. export function deferredUpdates<A>(fn: () => A): A {
    
  1407.   const previousPriority = getCurrentUpdatePriority();
    
  1408.   const prevTransition = ReactCurrentBatchConfig.transition;
    
  1409. 
    
  1410.   try {
    
  1411.     ReactCurrentBatchConfig.transition = null;
    
  1412.     setCurrentUpdatePriority(DefaultEventPriority);
    
  1413.     return fn();
    
  1414.   } finally {
    
  1415.     setCurrentUpdatePriority(previousPriority);
    
  1416.     ReactCurrentBatchConfig.transition = prevTransition;
    
  1417.   }
    
  1418. }
    
  1419. 
    
  1420. export function batchedUpdates<A, R>(fn: A => R, a: A): R {
    
  1421.   const prevExecutionContext = executionContext;
    
  1422.   executionContext |= BatchedContext;
    
  1423.   try {
    
  1424.     return fn(a);
    
  1425.   } finally {
    
  1426.     executionContext = prevExecutionContext;
    
  1427.     // If there were legacy sync updates, flush them at the end of the outer
    
  1428.     // most batchedUpdates-like method.
    
  1429.     if (
    
  1430.       executionContext === NoContext &&
    
  1431.       // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode.
    
  1432.       !(__DEV__ && ReactCurrentActQueue.isBatchingLegacy)
    
  1433.     ) {
    
  1434.       resetRenderTimer();
    
  1435.       flushSyncWorkOnLegacyRootsOnly();
    
  1436.     }
    
  1437.   }
    
  1438. }
    
  1439. 
    
  1440. export function discreteUpdates<A, B, C, D, R>(
    
  1441.   fn: (A, B, C, D) => R,
    
  1442.   a: A,
    
  1443.   b: B,
    
  1444.   c: C,
    
  1445.   d: D,
    
  1446. ): R {
    
  1447.   const previousPriority = getCurrentUpdatePriority();
    
  1448.   const prevTransition = ReactCurrentBatchConfig.transition;
    
  1449.   try {
    
  1450.     ReactCurrentBatchConfig.transition = null;
    
  1451.     setCurrentUpdatePriority(DiscreteEventPriority);
    
  1452.     return fn(a, b, c, d);
    
  1453.   } finally {
    
  1454.     setCurrentUpdatePriority(previousPriority);
    
  1455.     ReactCurrentBatchConfig.transition = prevTransition;
    
  1456.     if (executionContext === NoContext) {
    
  1457.       resetRenderTimer();
    
  1458.     }
    
  1459.   }
    
  1460. }
    
  1461. 
    
  1462. // Overload the definition to the two valid signatures.
    
  1463. // Warning, this opts-out of checking the function body.
    
  1464. // eslint-disable-next-line no-unused-vars
    
  1465. declare function flushSync<R>(fn: () => R): R;
    
  1466. // eslint-disable-next-line no-redeclare
    
  1467. declare function flushSync(void): void;
    
  1468. // eslint-disable-next-line no-redeclare
    
  1469. export function flushSync<R>(fn: (() => R) | void): R | void {
    
  1470.   // In legacy mode, we flush pending passive effects at the beginning of the
    
  1471.   // next event, not at the end of the previous one.
    
  1472.   if (
    
  1473.     rootWithPendingPassiveEffects !== null &&
    
  1474.     rootWithPendingPassiveEffects.tag === LegacyRoot &&
    
  1475.     (executionContext & (RenderContext | CommitContext)) === NoContext
    
  1476.   ) {
    
  1477.     flushPassiveEffects();
    
  1478.   }
    
  1479. 
    
  1480.   const prevExecutionContext = executionContext;
    
  1481.   executionContext |= BatchedContext;
    
  1482. 
    
  1483.   const prevTransition = ReactCurrentBatchConfig.transition;
    
  1484.   const previousPriority = getCurrentUpdatePriority();
    
  1485. 
    
  1486.   try {
    
  1487.     ReactCurrentBatchConfig.transition = null;
    
  1488.     setCurrentUpdatePriority(DiscreteEventPriority);
    
  1489.     if (fn) {
    
  1490.       return fn();
    
  1491.     } else {
    
  1492.       return undefined;
    
  1493.     }
    
  1494.   } finally {
    
  1495.     setCurrentUpdatePriority(previousPriority);
    
  1496.     ReactCurrentBatchConfig.transition = prevTransition;
    
  1497. 
    
  1498.     executionContext = prevExecutionContext;
    
  1499.     // Flush the immediate callbacks that were scheduled during this batch.
    
  1500.     // Note that this will happen even if batchedUpdates is higher up
    
  1501.     // the stack.
    
  1502.     if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
    
  1503.       flushSyncWorkOnAllRoots();
    
  1504.     }
    
  1505.   }
    
  1506. }
    
  1507. 
    
  1508. export function isAlreadyRendering(): boolean {
    
  1509.   // Used by the renderer to print a warning if certain APIs are called from
    
  1510.   // the wrong context.
    
  1511.   return (
    
  1512.     __DEV__ &&
    
  1513.     (executionContext & (RenderContext | CommitContext)) !== NoContext
    
  1514.   );
    
  1515. }
    
  1516. 
    
  1517. export function isInvalidExecutionContextForEventFunction(): boolean {
    
  1518.   // Used to throw if certain APIs are called from the wrong context.
    
  1519.   return (executionContext & RenderContext) !== NoContext;
    
  1520. }
    
  1521. 
    
  1522. // This is called by the HiddenContext module when we enter or leave a
    
  1523. // hidden subtree. The stack logic is managed there because that's the only
    
  1524. // place that ever modifies it. Which module it lives in doesn't matter for
    
  1525. // performance because this function will get inlined regardless
    
  1526. export function setEntangledRenderLanes(newEntangledRenderLanes: Lanes) {
    
  1527.   entangledRenderLanes = newEntangledRenderLanes;
    
  1528. }
    
  1529. 
    
  1530. export function getEntangledRenderLanes(): Lanes {
    
  1531.   return entangledRenderLanes;
    
  1532. }
    
  1533. 
    
  1534. function resetWorkInProgressStack() {
    
  1535.   if (workInProgress === null) return;
    
  1536.   let interruptedWork;
    
  1537.   if (workInProgressSuspendedReason === NotSuspended) {
    
  1538.     // Normal case. Work-in-progress hasn't started yet. Unwind all
    
  1539.     // its parents.
    
  1540.     interruptedWork = workInProgress.return;
    
  1541.   } else {
    
  1542.     // Work-in-progress is in suspended state. Reset the work loop and unwind
    
  1543.     // both the suspended fiber and all its parents.
    
  1544.     resetSuspendedWorkLoopOnUnwind(workInProgress);
    
  1545.     interruptedWork = workInProgress;
    
  1546.   }
    
  1547.   while (interruptedWork !== null) {
    
  1548.     const current = interruptedWork.alternate;
    
  1549.     unwindInterruptedWork(
    
  1550.       current,
    
  1551.       interruptedWork,
    
  1552.       workInProgressRootRenderLanes,
    
  1553.     );
    
  1554.     interruptedWork = interruptedWork.return;
    
  1555.   }
    
  1556.   workInProgress = null;
    
  1557. }
    
  1558. 
    
  1559. function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
    
  1560.   root.finishedWork = null;
    
  1561.   root.finishedLanes = NoLanes;
    
  1562. 
    
  1563.   const timeoutHandle = root.timeoutHandle;
    
  1564.   if (timeoutHandle !== noTimeout) {
    
  1565.     // The root previous suspended and scheduled a timeout to commit a fallback
    
  1566.     // state. Now that we have additional work, cancel the timeout.
    
  1567.     root.timeoutHandle = noTimeout;
    
  1568.     // $FlowFixMe[incompatible-call] Complains noTimeout is not a TimeoutID, despite the check above
    
  1569.     cancelTimeout(timeoutHandle);
    
  1570.   }
    
  1571.   const cancelPendingCommit = root.cancelPendingCommit;
    
  1572.   if (cancelPendingCommit !== null) {
    
  1573.     root.cancelPendingCommit = null;
    
  1574.     cancelPendingCommit();
    
  1575.   }
    
  1576. 
    
  1577.   resetWorkInProgressStack();
    
  1578.   workInProgressRoot = root;
    
  1579.   const rootWorkInProgress = createWorkInProgress(root.current, null);
    
  1580.   workInProgress = rootWorkInProgress;
    
  1581.   workInProgressRootRenderLanes = lanes;
    
  1582.   workInProgressSuspendedReason = NotSuspended;
    
  1583.   workInProgressThrownValue = null;
    
  1584.   workInProgressRootDidAttachPingListener = false;
    
  1585.   workInProgressRootExitStatus = RootInProgress;
    
  1586.   workInProgressRootFatalError = null;
    
  1587.   workInProgressRootSkippedLanes = NoLanes;
    
  1588.   workInProgressRootInterleavedUpdatedLanes = NoLanes;
    
  1589.   workInProgressRootRenderPhaseUpdatedLanes = NoLanes;
    
  1590.   workInProgressRootPingedLanes = NoLanes;
    
  1591.   workInProgressDeferredLane = NoLane;
    
  1592.   workInProgressRootConcurrentErrors = null;
    
  1593.   workInProgressRootRecoverableErrors = null;
    
  1594. 
    
  1595.   // Get the lanes that are entangled with whatever we're about to render. We
    
  1596.   // track these separately so we can distinguish the priority of the render
    
  1597.   // task from the priority of the lanes it is entangled with. For example, a
    
  1598.   // transition may not be allowed to finish unless it includes the Sync lane,
    
  1599.   // which is currently suspended. We should be able to render the Transition
    
  1600.   // and Sync lane in the same batch, but at Transition priority, because the
    
  1601.   // Sync lane already suspended.
    
  1602.   entangledRenderLanes = getEntangledLanes(root, lanes);
    
  1603. 
    
  1604.   finishQueueingConcurrentUpdates();
    
  1605. 
    
  1606.   if (__DEV__) {
    
  1607.     ReactStrictModeWarnings.discardPendingWarnings();
    
  1608.   }
    
  1609. 
    
  1610.   return rootWorkInProgress;
    
  1611. }
    
  1612. 
    
  1613. function resetSuspendedWorkLoopOnUnwind(fiber: Fiber) {
    
  1614.   // Reset module-level state that was set during the render phase.
    
  1615.   resetContextDependencies();
    
  1616.   resetHooksOnUnwind(fiber);
    
  1617.   resetChildReconcilerOnUnwind();
    
  1618. }
    
  1619. 
    
  1620. function handleThrow(root: FiberRoot, thrownValue: any): void {
    
  1621.   // A component threw an exception. Usually this is because it suspended, but
    
  1622.   // it also includes regular program errors.
    
  1623.   //
    
  1624.   // We're either going to unwind the stack to show a Suspense or error
    
  1625.   // boundary, or we're going to replay the component again. Like after a
    
  1626.   // promise resolves.
    
  1627.   //
    
  1628.   // Until we decide whether we're going to unwind or replay, we should preserve
    
  1629.   // the current state of the work loop without resetting anything.
    
  1630.   //
    
  1631.   // If we do decide to unwind the stack, module-level variables will be reset
    
  1632.   // in resetSuspendedWorkLoopOnUnwind.
    
  1633. 
    
  1634.   // These should be reset immediately because they're only supposed to be set
    
  1635.   // when React is executing user code.
    
  1636.   resetHooksAfterThrow();
    
  1637.   resetCurrentDebugFiberInDEV();
    
  1638.   ReactCurrentOwner.current = null;
    
  1639. 
    
  1640.   if (thrownValue === SuspenseException) {
    
  1641.     // This is a special type of exception used for Suspense. For historical
    
  1642.     // reasons, the rest of the Suspense implementation expects the thrown value
    
  1643.     // to be a thenable, because before `use` existed that was the (unstable)
    
  1644.     // API for suspending. This implementation detail can change later, once we
    
  1645.     // deprecate the old API in favor of `use`.
    
  1646.     thrownValue = getSuspendedThenable();
    
  1647.     workInProgressSuspendedReason =
    
  1648.       shouldRemainOnPreviousScreen() &&
    
  1649.       // Check if there are other pending updates that might possibly unblock this
    
  1650.       // component from suspending. This mirrors the check in
    
  1651.       // renderDidSuspendDelayIfPossible. We should attempt to unify them somehow.
    
  1652.       // TODO: Consider unwinding immediately, using the
    
  1653.       // SuspendedOnHydration mechanism.
    
  1654.       !includesNonIdleWork(workInProgressRootSkippedLanes) &&
    
  1655.       !includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)
    
  1656.         ? // Suspend work loop until data resolves
    
  1657.           SuspendedOnData
    
  1658.         : // Don't suspend work loop, except to check if the data has
    
  1659.           // immediately resolved (i.e. in a microtask). Otherwise, trigger the
    
  1660.           // nearest Suspense fallback.
    
  1661.           SuspendedOnImmediate;
    
  1662.   } else if (thrownValue === SuspenseyCommitException) {
    
  1663.     thrownValue = getSuspendedThenable();
    
  1664.     workInProgressSuspendedReason = SuspendedOnInstance;
    
  1665.   } else if (thrownValue === SelectiveHydrationException) {
    
  1666.     // An update flowed into a dehydrated boundary. Before we can apply the
    
  1667.     // update, we need to finish hydrating. Interrupt the work-in-progress
    
  1668.     // render so we can restart at the hydration lane.
    
  1669.     //
    
  1670.     // The ideal implementation would be able to switch contexts without
    
  1671.     // unwinding the current stack.
    
  1672.     //
    
  1673.     // We could name this something more general but as of now it's the only
    
  1674.     // case where we think this should happen.
    
  1675.     workInProgressSuspendedReason = SuspendedOnHydration;
    
  1676.   } else {
    
  1677.     // This is a regular error.
    
  1678.     const isWakeable =
    
  1679.       thrownValue !== null &&
    
  1680.       typeof thrownValue === 'object' &&
    
  1681.       typeof thrownValue.then === 'function';
    
  1682. 
    
  1683.     workInProgressSuspendedReason = isWakeable
    
  1684.       ? // A wakeable object was thrown by a legacy Suspense implementation.
    
  1685.         // This has slightly different behavior than suspending with `use`.
    
  1686.         SuspendedOnDeprecatedThrowPromise
    
  1687.       : // This is a regular error. If something earlier in the component already
    
  1688.         // suspended, we must clear the thenable state to unblock the work loop.
    
  1689.         SuspendedOnError;
    
  1690.   }
    
  1691. 
    
  1692.   workInProgressThrownValue = thrownValue;
    
  1693. 
    
  1694.   const erroredWork = workInProgress;
    
  1695.   if (erroredWork === null) {
    
  1696.     // This is a fatal error
    
  1697.     workInProgressRootExitStatus = RootFatalErrored;
    
  1698.     workInProgressRootFatalError = thrownValue;
    
  1699.     return;
    
  1700.   }
    
  1701. 
    
  1702.   if (enableProfilerTimer && erroredWork.mode & ProfileMode) {
    
  1703.     // Record the time spent rendering before an error was thrown. This
    
  1704.     // avoids inaccurate Profiler durations in the case of a
    
  1705.     // suspended render.
    
  1706.     stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);
    
  1707.   }
    
  1708. 
    
  1709.   if (enableSchedulingProfiler) {
    
  1710.     markComponentRenderStopped();
    
  1711.     switch (workInProgressSuspendedReason) {
    
  1712.       case SuspendedOnError: {
    
  1713.         markComponentErrored(
    
  1714.           erroredWork,
    
  1715.           thrownValue,
    
  1716.           workInProgressRootRenderLanes,
    
  1717.         );
    
  1718.         break;
    
  1719.       }
    
  1720.       case SuspendedOnData:
    
  1721.       case SuspendedOnImmediate:
    
  1722.       case SuspendedOnDeprecatedThrowPromise:
    
  1723.       case SuspendedAndReadyToContinue: {
    
  1724.         const wakeable: Wakeable = (thrownValue: any);
    
  1725.         markComponentSuspended(
    
  1726.           erroredWork,
    
  1727.           wakeable,
    
  1728.           workInProgressRootRenderLanes,
    
  1729.         );
    
  1730.         break;
    
  1731.       }
    
  1732.       case SuspendedOnInstance: {
    
  1733.         // This is conceptually like a suspend, but it's not associated with
    
  1734.         // a particular wakeable. It's associated with a host resource (e.g.
    
  1735.         // a CSS file or an image) that hasn't loaded yet. DevTools doesn't
    
  1736.         // handle this currently.
    
  1737.         break;
    
  1738.       }
    
  1739.       case SuspendedOnHydration: {
    
  1740.         // This is conceptually like a suspend, but it's not associated with
    
  1741.         // a particular wakeable. DevTools doesn't seem to care about this case,
    
  1742.         // currently. It's similar to if the component were interrupted, which
    
  1743.         // we don't mark with a special function.
    
  1744.         break;
    
  1745.       }
    
  1746.     }
    
  1747.   }
    
  1748. }
    
  1749. 
    
  1750. export function shouldRemainOnPreviousScreen(): boolean {
    
  1751.   // This is asking whether it's better to suspend the transition and remain
    
  1752.   // on the previous screen, versus showing a fallback as soon as possible. It
    
  1753.   // takes into account both the priority of render and also whether showing a
    
  1754.   // fallback would produce a desirable user experience.
    
  1755. 
    
  1756.   const handler = getSuspenseHandler();
    
  1757.   if (handler === null) {
    
  1758.     // There's no Suspense boundary that can provide a fallback. We have no
    
  1759.     // choice but to remain on the previous screen.
    
  1760.     // NOTE: We do this even for sync updates, for lack of any better option. In
    
  1761.     // the future, we may change how we handle this, like by putting the whole
    
  1762.     // root into a "detached" mode.
    
  1763.     return true;
    
  1764.   }
    
  1765. 
    
  1766.   // TODO: Once `use` has fully replaced the `throw promise` pattern, we should
    
  1767.   // be able to remove the equivalent check in finishConcurrentRender, and rely
    
  1768.   // just on this one.
    
  1769.   if (includesOnlyTransitions(workInProgressRootRenderLanes)) {
    
  1770.     if (getShellBoundary() === null) {
    
  1771.       // We're rendering inside the "shell" of the app. Activating the nearest
    
  1772.       // fallback would cause visible content to disappear. It's better to
    
  1773.       // suspend the transition and remain on the previous screen.
    
  1774.       return true;
    
  1775.     } else {
    
  1776.       // We're rendering content that wasn't part of the previous screen.
    
  1777.       // Rather than block the transition, it's better to show a fallback as
    
  1778.       // soon as possible. The appearance of any nested fallbacks will be
    
  1779.       // throttled to avoid jank.
    
  1780.       return false;
    
  1781.     }
    
  1782.   }
    
  1783. 
    
  1784.   if (
    
  1785.     includesOnlyRetries(workInProgressRootRenderLanes) ||
    
  1786.     // In this context, an OffscreenLane counts as a Retry
    
  1787.     // TODO: It's become increasingly clear that Retries and Offscreen are
    
  1788.     // deeply connected. They probably can be unified further.
    
  1789.     includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
    
  1790.   ) {
    
  1791.     // During a retry, we can suspend rendering if the nearest Suspense boundary
    
  1792.     // is the boundary of the "shell", because we're guaranteed not to block
    
  1793.     // any new content from appearing.
    
  1794.     //
    
  1795.     // The reason we must check if this is a retry is because it guarantees
    
  1796.     // that suspending the work loop won't block an actual update, because
    
  1797.     // retries don't "update" anything; they fill in fallbacks that were left
    
  1798.     // behind by a previous transition.
    
  1799.     return handler === getShellBoundary();
    
  1800.   }
    
  1801. 
    
  1802.   // For all other Lanes besides Transitions and Retries, we should not wait
    
  1803.   // for the data to load.
    
  1804.   return false;
    
  1805. }
    
  1806. 
    
  1807. function pushDispatcher(container: any) {
    
  1808.   const prevDispatcher = ReactCurrentDispatcher.current;
    
  1809.   ReactCurrentDispatcher.current = ContextOnlyDispatcher;
    
  1810.   if (prevDispatcher === null) {
    
  1811.     // The React isomorphic package does not include a default dispatcher.
    
  1812.     // Instead the first renderer will lazily attach one, in order to give
    
  1813.     // nicer error messages.
    
  1814.     return ContextOnlyDispatcher;
    
  1815.   } else {
    
  1816.     return prevDispatcher;
    
  1817.   }
    
  1818. }
    
  1819. 
    
  1820. function popDispatcher(prevDispatcher: any) {
    
  1821.   ReactCurrentDispatcher.current = prevDispatcher;
    
  1822. }
    
  1823. 
    
  1824. function pushCacheDispatcher() {
    
  1825.   if (enableCache) {
    
  1826.     const prevCacheDispatcher = ReactCurrentCache.current;
    
  1827.     ReactCurrentCache.current = DefaultCacheDispatcher;
    
  1828.     return prevCacheDispatcher;
    
  1829.   } else {
    
  1830.     return null;
    
  1831.   }
    
  1832. }
    
  1833. 
    
  1834. function popCacheDispatcher(prevCacheDispatcher: any) {
    
  1835.   if (enableCache) {
    
  1836.     ReactCurrentCache.current = prevCacheDispatcher;
    
  1837.   }
    
  1838. }
    
  1839. 
    
  1840. export function markCommitTimeOfFallback() {
    
  1841.   globalMostRecentFallbackTime = now();
    
  1842. }
    
  1843. 
    
  1844. export function markSkippedUpdateLanes(lane: Lane | Lanes): void {
    
  1845.   workInProgressRootSkippedLanes = mergeLanes(
    
  1846.     lane,
    
  1847.     workInProgressRootSkippedLanes,
    
  1848.   );
    
  1849. }
    
  1850. 
    
  1851. export function renderDidSuspend(): void {
    
  1852.   if (workInProgressRootExitStatus === RootInProgress) {
    
  1853.     workInProgressRootExitStatus = RootSuspended;
    
  1854.   }
    
  1855. }
    
  1856. 
    
  1857. export function renderDidSuspendDelayIfPossible(): void {
    
  1858.   workInProgressRootExitStatus = RootSuspendedWithDelay;
    
  1859. 
    
  1860.   // Check if there are updates that we skipped tree that might have unblocked
    
  1861.   // this render.
    
  1862.   if (
    
  1863.     (includesNonIdleWork(workInProgressRootSkippedLanes) ||
    
  1864.       includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) &&
    
  1865.     workInProgressRoot !== null
    
  1866.   ) {
    
  1867.     // Mark the current render as suspended so that we switch to working on
    
  1868.     // the updates that were skipped. Usually we only suspend at the end of
    
  1869.     // the render phase.
    
  1870.     // TODO: We should probably always mark the root as suspended immediately
    
  1871.     // (inside this function), since by suspending at the end of the render
    
  1872.     // phase introduces a potential mistake where we suspend lanes that were
    
  1873.     // pinged or updated while we were rendering.
    
  1874.     // TODO: Consider unwinding immediately, using the
    
  1875.     // SuspendedOnHydration mechanism.
    
  1876.     markRootSuspended(
    
  1877.       workInProgressRoot,
    
  1878.       workInProgressRootRenderLanes,
    
  1879.       workInProgressDeferredLane,
    
  1880.     );
    
  1881.   }
    
  1882. }
    
  1883. 
    
  1884. export function renderDidError(error: CapturedValue<mixed>) {
    
  1885.   if (workInProgressRootExitStatus !== RootSuspendedWithDelay) {
    
  1886.     workInProgressRootExitStatus = RootErrored;
    
  1887.   }
    
  1888.   if (workInProgressRootConcurrentErrors === null) {
    
  1889.     workInProgressRootConcurrentErrors = [error];
    
  1890.   } else {
    
  1891.     workInProgressRootConcurrentErrors.push(error);
    
  1892.   }
    
  1893. }
    
  1894. 
    
  1895. // Called during render to determine if anything has suspended.
    
  1896. // Returns false if we're not sure.
    
  1897. export function renderHasNotSuspendedYet(): boolean {
    
  1898.   // If something errored or completed, we can't really be sure,
    
  1899.   // so those are false.
    
  1900.   return workInProgressRootExitStatus === RootInProgress;
    
  1901. }
    
  1902. 
    
  1903. // TODO: Over time, this function and renderRootConcurrent have become more
    
  1904. // and more similar. Not sure it makes sense to maintain forked paths. Consider
    
  1905. // unifying them again.
    
  1906. function renderRootSync(root: FiberRoot, lanes: Lanes) {
    
  1907.   const prevExecutionContext = executionContext;
    
  1908.   executionContext |= RenderContext;
    
  1909.   const prevDispatcher = pushDispatcher(root.containerInfo);
    
  1910.   const prevCacheDispatcher = pushCacheDispatcher();
    
  1911. 
    
  1912.   // If the root or lanes have changed, throw out the existing stack
    
  1913.   // and prepare a fresh one. Otherwise we'll continue where we left off.
    
  1914.   if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
    
  1915.     if (enableUpdaterTracking) {
    
  1916.       if (isDevToolsPresent) {
    
  1917.         const memoizedUpdaters = root.memoizedUpdaters;
    
  1918.         if (memoizedUpdaters.size > 0) {
    
  1919.           restorePendingUpdaters(root, workInProgressRootRenderLanes);
    
  1920.           memoizedUpdaters.clear();
    
  1921.         }
    
  1922. 
    
  1923.         // At this point, move Fibers that scheduled the upcoming work from the Map to the Set.
    
  1924.         // If we bailout on this work, we'll move them back (like above).
    
  1925.         // It's important to move them now in case the work spawns more work at the same priority with different updaters.
    
  1926.         // That way we can keep the current update and future updates separate.
    
  1927.         movePendingFibersToMemoized(root, lanes);
    
  1928.       }
    
  1929.     }
    
  1930. 
    
  1931.     workInProgressTransitions = getTransitionsForLanes(root, lanes);
    
  1932.     prepareFreshStack(root, lanes);
    
  1933.   }
    
  1934. 
    
  1935.   if (__DEV__) {
    
  1936.     if (enableDebugTracing) {
    
  1937.       logRenderStarted(lanes);
    
  1938.     }
    
  1939.   }
    
  1940. 
    
  1941.   if (enableSchedulingProfiler) {
    
  1942.     markRenderStarted(lanes);
    
  1943.   }
    
  1944. 
    
  1945.   let didSuspendInShell = false;
    
  1946.   outer: do {
    
  1947.     try {
    
  1948.       if (
    
  1949.         workInProgressSuspendedReason !== NotSuspended &&
    
  1950.         workInProgress !== null
    
  1951.       ) {
    
  1952.         // The work loop is suspended. During a synchronous render, we don't
    
  1953.         // yield to the main thread. Immediately unwind the stack. This will
    
  1954.         // trigger either a fallback or an error boundary.
    
  1955.         // TODO: For discrete and "default" updates (anything that's not
    
  1956.         // flushSync), we want to wait for the microtasks the flush before
    
  1957.         // unwinding. Will probably implement this using renderRootConcurrent,
    
  1958.         // or merge renderRootSync and renderRootConcurrent into the same
    
  1959.         // function and fork the behavior some other way.
    
  1960.         const unitOfWork = workInProgress;
    
  1961.         const thrownValue = workInProgressThrownValue;
    
  1962.         switch (workInProgressSuspendedReason) {
    
  1963.           case SuspendedOnHydration: {
    
  1964.             // Selective hydration. An update flowed into a dehydrated tree.
    
  1965.             // Interrupt the current render so the work loop can switch to the
    
  1966.             // hydration lane.
    
  1967.             resetWorkInProgressStack();
    
  1968.             workInProgressRootExitStatus = RootDidNotComplete;
    
  1969.             break outer;
    
  1970.           }
    
  1971.           case SuspendedOnImmediate:
    
  1972.           case SuspendedOnData: {
    
  1973.             if (!didSuspendInShell && getSuspenseHandler() === null) {
    
  1974.               didSuspendInShell = true;
    
  1975.             }
    
  1976.             // Intentional fallthrough
    
  1977.           }
    
  1978.           default: {
    
  1979.             // Unwind then continue with the normal work loop.
    
  1980.             workInProgressSuspendedReason = NotSuspended;
    
  1981.             workInProgressThrownValue = null;
    
  1982.             throwAndUnwindWorkLoop(unitOfWork, thrownValue);
    
  1983.             break;
    
  1984.           }
    
  1985.         }
    
  1986.       }
    
  1987.       workLoopSync();
    
  1988.       break;
    
  1989.     } catch (thrownValue) {
    
  1990.       handleThrow(root, thrownValue);
    
  1991.     }
    
  1992.   } while (true);
    
  1993. 
    
  1994.   // Check if something suspended in the shell. We use this to detect an
    
  1995.   // infinite ping loop caused by an uncached promise.
    
  1996.   //
    
  1997.   // Only increment this counter once per synchronous render attempt across the
    
  1998.   // whole tree. Even if there are many sibling components that suspend, this
    
  1999.   // counter only gets incremented once.
    
  2000.   if (didSuspendInShell) {
    
  2001.     root.shellSuspendCounter++;
    
  2002.   }
    
  2003. 
    
  2004.   resetContextDependencies();
    
  2005. 
    
  2006.   executionContext = prevExecutionContext;
    
  2007.   popDispatcher(prevDispatcher);
    
  2008.   popCacheDispatcher(prevCacheDispatcher);
    
  2009. 
    
  2010.   if (workInProgress !== null) {
    
  2011.     // This is a sync render, so we should have finished the whole tree.
    
  2012.     throw new Error(
    
  2013.       'Cannot commit an incomplete root. This error is likely caused by a ' +
    
  2014.         'bug in React. Please file an issue.',
    
  2015.     );
    
  2016.   }
    
  2017. 
    
  2018.   if (__DEV__) {
    
  2019.     if (enableDebugTracing) {
    
  2020.       logRenderStopped();
    
  2021.     }
    
  2022.   }
    
  2023. 
    
  2024.   if (enableSchedulingProfiler) {
    
  2025.     markRenderStopped();
    
  2026.   }
    
  2027. 
    
  2028.   // Set this to null to indicate there's no in-progress render.
    
  2029.   workInProgressRoot = null;
    
  2030.   workInProgressRootRenderLanes = NoLanes;
    
  2031. 
    
  2032.   // It's safe to process the queue now that the render phase is complete.
    
  2033.   finishQueueingConcurrentUpdates();
    
  2034. 
    
  2035.   return workInProgressRootExitStatus;
    
  2036. }
    
  2037. 
    
  2038. // The work loop is an extremely hot path. Tell Closure not to inline it.
    
  2039. /** @noinline */
    
  2040. function workLoopSync() {
    
  2041.   // Perform work without checking if we need to yield between fiber.
    
  2042.   while (workInProgress !== null) {
    
  2043.     performUnitOfWork(workInProgress);
    
  2044.   }
    
  2045. }
    
  2046. 
    
  2047. function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
    
  2048.   const prevExecutionContext = executionContext;
    
  2049.   executionContext |= RenderContext;
    
  2050.   const prevDispatcher = pushDispatcher(root.containerInfo);
    
  2051.   const prevCacheDispatcher = pushCacheDispatcher();
    
  2052. 
    
  2053.   // If the root or lanes have changed, throw out the existing stack
    
  2054.   // and prepare a fresh one. Otherwise we'll continue where we left off.
    
  2055.   if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
    
  2056.     if (enableUpdaterTracking) {
    
  2057.       if (isDevToolsPresent) {
    
  2058.         const memoizedUpdaters = root.memoizedUpdaters;
    
  2059.         if (memoizedUpdaters.size > 0) {
    
  2060.           restorePendingUpdaters(root, workInProgressRootRenderLanes);
    
  2061.           memoizedUpdaters.clear();
    
  2062.         }
    
  2063. 
    
  2064.         // At this point, move Fibers that scheduled the upcoming work from the Map to the Set.
    
  2065.         // If we bailout on this work, we'll move them back (like above).
    
  2066.         // It's important to move them now in case the work spawns more work at the same priority with different updaters.
    
  2067.         // That way we can keep the current update and future updates separate.
    
  2068.         movePendingFibersToMemoized(root, lanes);
    
  2069.       }
    
  2070.     }
    
  2071. 
    
  2072.     workInProgressTransitions = getTransitionsForLanes(root, lanes);
    
  2073.     resetRenderTimer();
    
  2074.     prepareFreshStack(root, lanes);
    
  2075.   }
    
  2076. 
    
  2077.   if (__DEV__) {
    
  2078.     if (enableDebugTracing) {
    
  2079.       logRenderStarted(lanes);
    
  2080.     }
    
  2081.   }
    
  2082. 
    
  2083.   if (enableSchedulingProfiler) {
    
  2084.     markRenderStarted(lanes);
    
  2085.   }
    
  2086. 
    
  2087.   outer: do {
    
  2088.     try {
    
  2089.       if (
    
  2090.         workInProgressSuspendedReason !== NotSuspended &&
    
  2091.         workInProgress !== null
    
  2092.       ) {
    
  2093.         // The work loop is suspended. We need to either unwind the stack or
    
  2094.         // replay the suspended component.
    
  2095.         const unitOfWork = workInProgress;
    
  2096.         const thrownValue = workInProgressThrownValue;
    
  2097.         resumeOrUnwind: switch (workInProgressSuspendedReason) {
    
  2098.           case SuspendedOnError: {
    
  2099.             // Unwind then continue with the normal work loop.
    
  2100.             workInProgressSuspendedReason = NotSuspended;
    
  2101.             workInProgressThrownValue = null;
    
  2102.             throwAndUnwindWorkLoop(unitOfWork, thrownValue);
    
  2103.             break;
    
  2104.           }
    
  2105.           case SuspendedOnData: {
    
  2106.             const thenable: Thenable<mixed> = (thrownValue: any);
    
  2107.             if (isThenableResolved(thenable)) {
    
  2108.               // The data resolved. Try rendering the component again.
    
  2109.               workInProgressSuspendedReason = NotSuspended;
    
  2110.               workInProgressThrownValue = null;
    
  2111.               replaySuspendedUnitOfWork(unitOfWork);
    
  2112.               break;
    
  2113.             }
    
  2114.             // The work loop is suspended on data. We should wait for it to
    
  2115.             // resolve before continuing to render.
    
  2116.             // TODO: Handle the case where the promise resolves synchronously.
    
  2117.             // Usually this is handled when we instrument the promise to add a
    
  2118.             // `status` field, but if the promise already has a status, we won't
    
  2119.             // have added a listener until right here.
    
  2120.             const onResolution = () => {
    
  2121.               // Check if the root is still suspended on this promise.
    
  2122.               if (
    
  2123.                 workInProgressSuspendedReason === SuspendedOnData &&
    
  2124.                 workInProgressRoot === root
    
  2125.               ) {
    
  2126.                 // Mark the root as ready to continue rendering.
    
  2127.                 workInProgressSuspendedReason = SuspendedAndReadyToContinue;
    
  2128.               }
    
  2129.               // Ensure the root is scheduled. We should do this even if we're
    
  2130.               // currently working on a different root, so that we resume
    
  2131.               // rendering later.
    
  2132.               ensureRootIsScheduled(root);
    
  2133.             };
    
  2134.             thenable.then(onResolution, onResolution);
    
  2135.             break outer;
    
  2136.           }
    
  2137.           case SuspendedOnImmediate: {
    
  2138.             // If this fiber just suspended, it's possible the data is already
    
  2139.             // cached. Yield to the main thread to give it a chance to ping. If
    
  2140.             // it does, we can retry immediately without unwinding the stack.
    
  2141.             workInProgressSuspendedReason = SuspendedAndReadyToContinue;
    
  2142.             break outer;
    
  2143.           }
    
  2144.           case SuspendedOnInstance: {
    
  2145.             workInProgressSuspendedReason =
    
  2146.               SuspendedOnInstanceAndReadyToContinue;
    
  2147.             break outer;
    
  2148.           }
    
  2149.           case SuspendedAndReadyToContinue: {
    
  2150.             const thenable: Thenable<mixed> = (thrownValue: any);
    
  2151.             if (isThenableResolved(thenable)) {
    
  2152.               // The data resolved. Try rendering the component again.
    
  2153.               workInProgressSuspendedReason = NotSuspended;
    
  2154.               workInProgressThrownValue = null;
    
  2155.               replaySuspendedUnitOfWork(unitOfWork);
    
  2156.             } else {
    
  2157.               // Otherwise, unwind then continue with the normal work loop.
    
  2158.               workInProgressSuspendedReason = NotSuspended;
    
  2159.               workInProgressThrownValue = null;
    
  2160.               throwAndUnwindWorkLoop(unitOfWork, thrownValue);
    
  2161.             }
    
  2162.             break;
    
  2163.           }
    
  2164.           case SuspendedOnInstanceAndReadyToContinue: {
    
  2165.             switch (workInProgress.tag) {
    
  2166.               case HostComponent:
    
  2167.               case HostHoistable:
    
  2168.               case HostSingleton: {
    
  2169.                 // Before unwinding the stack, check one more time if the
    
  2170.                 // instance is ready. It may have loaded when React yielded to
    
  2171.                 // the main thread.
    
  2172. 
    
  2173.                 // Assigning this to a constant so Flow knows the binding won't
    
  2174.                 // be mutated by `preloadInstance`.
    
  2175.                 const hostFiber = workInProgress;
    
  2176.                 const type = hostFiber.type;
    
  2177.                 const props = hostFiber.pendingProps;
    
  2178.                 const isReady = preloadInstance(type, props);
    
  2179.                 if (isReady) {
    
  2180.                   // The data resolved. Resume the work loop as if nothing
    
  2181.                   // suspended. Unlike when a user component suspends, we don't
    
  2182.                   // have to replay anything because the host fiber
    
  2183.                   // already completed.
    
  2184.                   workInProgressSuspendedReason = NotSuspended;
    
  2185.                   workInProgressThrownValue = null;
    
  2186.                   const sibling = hostFiber.sibling;
    
  2187.                   if (sibling !== null) {
    
  2188.                     workInProgress = sibling;
    
  2189.                   } else {
    
  2190.                     const returnFiber = hostFiber.return;
    
  2191.                     if (returnFiber !== null) {
    
  2192.                       workInProgress = returnFiber;
    
  2193.                       completeUnitOfWork(returnFiber);
    
  2194.                     } else {
    
  2195.                       workInProgress = null;
    
  2196.                     }
    
  2197.                   }
    
  2198.                   break resumeOrUnwind;
    
  2199.                 }
    
  2200.                 break;
    
  2201.               }
    
  2202.               default: {
    
  2203.                 // This will fail gracefully but it's not correct, so log a
    
  2204.                 // warning in dev.
    
  2205.                 if (__DEV__) {
    
  2206.                   console.error(
    
  2207.                     'Unexpected type of fiber triggered a suspensey commit. ' +
    
  2208.                       'This is a bug in React.',
    
  2209.                   );
    
  2210.                 }
    
  2211.                 break;
    
  2212.               }
    
  2213.             }
    
  2214.             // Otherwise, unwind then continue with the normal work loop.
    
  2215.             workInProgressSuspendedReason = NotSuspended;
    
  2216.             workInProgressThrownValue = null;
    
  2217.             throwAndUnwindWorkLoop(unitOfWork, thrownValue);
    
  2218.             break;
    
  2219.           }
    
  2220.           case SuspendedOnDeprecatedThrowPromise: {
    
  2221.             // Suspended by an old implementation that uses the `throw promise`
    
  2222.             // pattern. The newer replaying behavior can cause subtle issues
    
  2223.             // like infinite ping loops. So we maintain the old behavior and
    
  2224.             // always unwind.
    
  2225.             workInProgressSuspendedReason = NotSuspended;
    
  2226.             workInProgressThrownValue = null;
    
  2227.             throwAndUnwindWorkLoop(unitOfWork, thrownValue);
    
  2228.             break;
    
  2229.           }
    
  2230.           case SuspendedOnHydration: {
    
  2231.             // Selective hydration. An update flowed into a dehydrated tree.
    
  2232.             // Interrupt the current render so the work loop can switch to the
    
  2233.             // hydration lane.
    
  2234.             resetWorkInProgressStack();
    
  2235.             workInProgressRootExitStatus = RootDidNotComplete;
    
  2236.             break outer;
    
  2237.           }
    
  2238.           default: {
    
  2239.             throw new Error(
    
  2240.               'Unexpected SuspendedReason. This is a bug in React.',
    
  2241.             );
    
  2242.           }
    
  2243.         }
    
  2244.       }
    
  2245. 
    
  2246.       if (__DEV__ && ReactCurrentActQueue.current !== null) {
    
  2247.         // `act` special case: If we're inside an `act` scope, don't consult
    
  2248.         // `shouldYield`. Always keep working until the render is complete.
    
  2249.         // This is not just an optimization: in a unit test environment, we
    
  2250.         // can't trust the result of `shouldYield`, because the host I/O is
    
  2251.         // likely mocked.
    
  2252.         workLoopSync();
    
  2253.       } else {
    
  2254.         workLoopConcurrent();
    
  2255.       }
    
  2256.       break;
    
  2257.     } catch (thrownValue) {
    
  2258.       handleThrow(root, thrownValue);
    
  2259.     }
    
  2260.   } while (true);
    
  2261.   resetContextDependencies();
    
  2262. 
    
  2263.   popDispatcher(prevDispatcher);
    
  2264.   popCacheDispatcher(prevCacheDispatcher);
    
  2265.   executionContext = prevExecutionContext;
    
  2266. 
    
  2267.   if (__DEV__) {
    
  2268.     if (enableDebugTracing) {
    
  2269.       logRenderStopped();
    
  2270.     }
    
  2271.   }
    
  2272. 
    
  2273.   // Check if the tree has completed.
    
  2274.   if (workInProgress !== null) {
    
  2275.     // Still work remaining.
    
  2276.     if (enableSchedulingProfiler) {
    
  2277.       markRenderYielded();
    
  2278.     }
    
  2279.     return RootInProgress;
    
  2280.   } else {
    
  2281.     // Completed the tree.
    
  2282.     if (enableSchedulingProfiler) {
    
  2283.       markRenderStopped();
    
  2284.     }
    
  2285. 
    
  2286.     // Set this to null to indicate there's no in-progress render.
    
  2287.     workInProgressRoot = null;
    
  2288.     workInProgressRootRenderLanes = NoLanes;
    
  2289. 
    
  2290.     // It's safe to process the queue now that the render phase is complete.
    
  2291.     finishQueueingConcurrentUpdates();
    
  2292. 
    
  2293.     // Return the final exit status.
    
  2294.     return workInProgressRootExitStatus;
    
  2295.   }
    
  2296. }
    
  2297. 
    
  2298. /** @noinline */
    
  2299. function workLoopConcurrent() {
    
  2300.   // Perform work until Scheduler asks us to yield
    
  2301.   while (workInProgress !== null && !shouldYield()) {
    
  2302.     // $FlowFixMe[incompatible-call] found when upgrading Flow
    
  2303.     performUnitOfWork(workInProgress);
    
  2304.   }
    
  2305. }
    
  2306. 
    
  2307. function performUnitOfWork(unitOfWork: Fiber): void {
    
  2308.   // The current, flushed, state of this fiber is the alternate. Ideally
    
  2309.   // nothing should rely on this, but relying on it here means that we don't
    
  2310.   // need an additional field on the work in progress.
    
  2311.   const current = unitOfWork.alternate;
    
  2312.   setCurrentDebugFiberInDEV(unitOfWork);
    
  2313. 
    
  2314.   let next;
    
  2315.   if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
    
  2316.     startProfilerTimer(unitOfWork);
    
  2317.     next = beginWork(current, unitOfWork, entangledRenderLanes);
    
  2318.     stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
    
  2319.   } else {
    
  2320.     next = beginWork(current, unitOfWork, entangledRenderLanes);
    
  2321.   }
    
  2322. 
    
  2323.   resetCurrentDebugFiberInDEV();
    
  2324.   unitOfWork.memoizedProps = unitOfWork.pendingProps;
    
  2325.   if (next === null) {
    
  2326.     // If this doesn't spawn new work, complete the current work.
    
  2327.     completeUnitOfWork(unitOfWork);
    
  2328.   } else {
    
  2329.     workInProgress = next;
    
  2330.   }
    
  2331. 
    
  2332.   ReactCurrentOwner.current = null;
    
  2333. }
    
  2334. 
    
  2335. function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
    
  2336.   // This is a fork of performUnitOfWork specifcally for replaying a fiber that
    
  2337.   // just suspended.
    
  2338.   //
    
  2339.   const current = unitOfWork.alternate;
    
  2340.   setCurrentDebugFiberInDEV(unitOfWork);
    
  2341. 
    
  2342.   let next;
    
  2343.   setCurrentDebugFiberInDEV(unitOfWork);
    
  2344.   const isProfilingMode =
    
  2345.     enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode;
    
  2346.   if (isProfilingMode) {
    
  2347.     startProfilerTimer(unitOfWork);
    
  2348.   }
    
  2349.   switch (unitOfWork.tag) {
    
  2350.     case IndeterminateComponent: {
    
  2351.       // Because it suspended with `use`, we can assume it's a
    
  2352.       // function component.
    
  2353.       unitOfWork.tag = FunctionComponent;
    
  2354.       // Fallthrough to the next branch.
    
  2355.     }
    
  2356.     case SimpleMemoComponent:
    
  2357.     case FunctionComponent: {
    
  2358.       // Resolve `defaultProps`. This logic is copied from `beginWork`.
    
  2359.       // TODO: Consider moving this switch statement into that module. Also,
    
  2360.       // could maybe use this as an opportunity to say `use` doesn't work with
    
  2361.       // `defaultProps` :)
    
  2362.       const Component = unitOfWork.type;
    
  2363.       const unresolvedProps = unitOfWork.pendingProps;
    
  2364.       const resolvedProps =
    
  2365.         unitOfWork.elementType === Component
    
  2366.           ? unresolvedProps
    
  2367.           : resolveDefaultProps(Component, unresolvedProps);
    
  2368.       let context: any;
    
  2369.       if (!disableLegacyContext) {
    
  2370.         const unmaskedContext = getUnmaskedContext(unitOfWork, Component, true);
    
  2371.         context = getMaskedContext(unitOfWork, unmaskedContext);
    
  2372.       }
    
  2373.       next = replayFunctionComponent(
    
  2374.         current,
    
  2375.         unitOfWork,
    
  2376.         resolvedProps,
    
  2377.         Component,
    
  2378.         context,
    
  2379.         workInProgressRootRenderLanes,
    
  2380.       );
    
  2381.       break;
    
  2382.     }
    
  2383.     case ForwardRef: {
    
  2384.       // Resolve `defaultProps`. This logic is copied from `beginWork`.
    
  2385.       // TODO: Consider moving this switch statement into that module. Also,
    
  2386.       // could maybe use this as an opportunity to say `use` doesn't work with
    
  2387.       // `defaultProps` :)
    
  2388.       const Component = unitOfWork.type.render;
    
  2389.       const unresolvedProps = unitOfWork.pendingProps;
    
  2390.       const resolvedProps =
    
  2391.         unitOfWork.elementType === Component
    
  2392.           ? unresolvedProps
    
  2393.           : resolveDefaultProps(Component, unresolvedProps);
    
  2394. 
    
  2395.       next = replayFunctionComponent(
    
  2396.         current,
    
  2397.         unitOfWork,
    
  2398.         resolvedProps,
    
  2399.         Component,
    
  2400.         unitOfWork.ref,
    
  2401.         workInProgressRootRenderLanes,
    
  2402.       );
    
  2403.       break;
    
  2404.     }
    
  2405.     case HostComponent: {
    
  2406.       // Some host components are stateful (that's how we implement form
    
  2407.       // actions) but we don't bother to reuse the memoized state because it's
    
  2408.       // not worth the extra code. The main reason to reuse the previous hooks
    
  2409.       // is to reuse uncached promises, but we happen to know that the only
    
  2410.       // promises that a host component might suspend on are definitely cached
    
  2411.       // because they are controlled by us. So don't bother.
    
  2412.       resetHooksOnUnwind(unitOfWork);
    
  2413.       // Fallthrough to the next branch.
    
  2414.     }
    
  2415.     default: {
    
  2416.       // Other types besides function components are reset completely before
    
  2417.       // being replayed. Currently this only happens when a Usable type is
    
  2418.       // reconciled — the reconciler will suspend.
    
  2419.       //
    
  2420.       // We reset the fiber back to its original state; however, this isn't
    
  2421.       // a full "unwind" because we're going to reuse the promises that were
    
  2422.       // reconciled previously. So it's intentional that we don't call
    
  2423.       // resetSuspendedWorkLoopOnUnwind here.
    
  2424.       unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes);
    
  2425.       unitOfWork = workInProgress = resetWorkInProgress(
    
  2426.         unitOfWork,
    
  2427.         entangledRenderLanes,
    
  2428.       );
    
  2429.       next = beginWork(current, unitOfWork, entangledRenderLanes);
    
  2430.       break;
    
  2431.     }
    
  2432.   }
    
  2433.   if (isProfilingMode) {
    
  2434.     stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
    
  2435.   }
    
  2436. 
    
  2437.   // The begin phase finished successfully without suspending. Return to the
    
  2438.   // normal work loop.
    
  2439. 
    
  2440.   resetCurrentDebugFiberInDEV();
    
  2441.   unitOfWork.memoizedProps = unitOfWork.pendingProps;
    
  2442.   if (next === null) {
    
  2443.     // If this doesn't spawn new work, complete the current work.
    
  2444.     completeUnitOfWork(unitOfWork);
    
  2445.   } else {
    
  2446.     workInProgress = next;
    
  2447.   }
    
  2448. 
    
  2449.   ReactCurrentOwner.current = null;
    
  2450. }
    
  2451. 
    
  2452. function throwAndUnwindWorkLoop(unitOfWork: Fiber, thrownValue: mixed) {
    
  2453.   // This is a fork of performUnitOfWork specifcally for unwinding a fiber
    
  2454.   // that threw an exception.
    
  2455.   //
    
  2456.   // Return to the normal work loop. This will unwind the stack, and potentially
    
  2457.   // result in showing a fallback.
    
  2458.   resetSuspendedWorkLoopOnUnwind(unitOfWork);
    
  2459. 
    
  2460.   const returnFiber = unitOfWork.return;
    
  2461.   if (returnFiber === null || workInProgressRoot === null) {
    
  2462.     // Expected to be working on a non-root fiber. This is a fatal error
    
  2463.     // because there's no ancestor that can handle it; the root is
    
  2464.     // supposed to capture all errors that weren't caught by an error
    
  2465.     // boundary.
    
  2466.     workInProgressRootExitStatus = RootFatalErrored;
    
  2467.     workInProgressRootFatalError = thrownValue;
    
  2468.     // Set `workInProgress` to null. This represents advancing to the next
    
  2469.     // sibling, or the parent if there are no siblings. But since the root
    
  2470.     // has no siblings nor a parent, we set it to null. Usually this is
    
  2471.     // handled by `completeUnitOfWork` or `unwindWork`, but since we're
    
  2472.     // intentionally not calling those, we need set it here.
    
  2473.     // TODO: Consider calling `unwindWork` to pop the contexts.
    
  2474.     workInProgress = null;
    
  2475.     return;
    
  2476.   }
    
  2477. 
    
  2478.   try {
    
  2479.     // Find and mark the nearest Suspense or error boundary that can handle
    
  2480.     // this "exception".
    
  2481.     throwException(
    
  2482.       workInProgressRoot,
    
  2483.       returnFiber,
    
  2484.       unitOfWork,
    
  2485.       thrownValue,
    
  2486.       workInProgressRootRenderLanes,
    
  2487.     );
    
  2488.   } catch (error) {
    
  2489.     // We had trouble processing the error. An example of this happening is
    
  2490.     // when accessing the `componentDidCatch` property of an error boundary
    
  2491.     // throws an error. A weird edge case. There's a regression test for this.
    
  2492.     // To prevent an infinite loop, bubble the error up to the next parent.
    
  2493.     workInProgress = returnFiber;
    
  2494.     throw error;
    
  2495.   }
    
  2496. 
    
  2497.   if (unitOfWork.flags & Incomplete) {
    
  2498.     // Unwind the stack until we reach the nearest boundary.
    
  2499.     unwindUnitOfWork(unitOfWork);
    
  2500.   } else {
    
  2501.     // Although the fiber suspended, we're intentionally going to commit it in
    
  2502.     // an inconsistent state. We can do this safely in cases where we know the
    
  2503.     // inconsistent tree will be hidden.
    
  2504.     //
    
  2505.     // This currently only applies to Legacy Suspense implementation, but we may
    
  2506.     // port a version of this to concurrent roots, too, when performing a
    
  2507.     // synchronous render. Because that will allow us to mutate the tree as we
    
  2508.     // go instead of buffering mutations until the end. Though it's unclear if
    
  2509.     // this particular path is how that would be implemented.
    
  2510.     completeUnitOfWork(unitOfWork);
    
  2511.   }
    
  2512. }
    
  2513. 
    
  2514. function completeUnitOfWork(unitOfWork: Fiber): void {
    
  2515.   // Attempt to complete the current unit of work, then move to the next
    
  2516.   // sibling. If there are no more siblings, return to the parent fiber.
    
  2517.   let completedWork: Fiber = unitOfWork;
    
  2518.   do {
    
  2519.     if (__DEV__) {
    
  2520.       if ((completedWork.flags & Incomplete) !== NoFlags) {
    
  2521.         // NOTE: If we re-enable sibling prerendering in some cases, this branch
    
  2522.         // is where we would switch to the unwinding path.
    
  2523.         console.error(
    
  2524.           'Internal React error: Expected this fiber to be complete, but ' +
    
  2525.             "it isn't. It should have been unwound. This is a bug in React.",
    
  2526.         );
    
  2527.       }
    
  2528.     }
    
  2529. 
    
  2530.     // The current, flushed, state of this fiber is the alternate. Ideally
    
  2531.     // nothing should rely on this, but relying on it here means that we don't
    
  2532.     // need an additional field on the work in progress.
    
  2533.     const current = completedWork.alternate;
    
  2534.     const returnFiber = completedWork.return;
    
  2535. 
    
  2536.     setCurrentDebugFiberInDEV(completedWork);
    
  2537.     let next;
    
  2538.     if (!enableProfilerTimer || (completedWork.mode & ProfileMode) === NoMode) {
    
  2539.       next = completeWork(current, completedWork, entangledRenderLanes);
    
  2540.     } else {
    
  2541.       startProfilerTimer(completedWork);
    
  2542.       next = completeWork(current, completedWork, entangledRenderLanes);
    
  2543.       // Update render duration assuming we didn't error.
    
  2544.       stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
    
  2545.     }
    
  2546.     resetCurrentDebugFiberInDEV();
    
  2547. 
    
  2548.     if (next !== null) {
    
  2549.       // Completing this fiber spawned new work. Work on that next.
    
  2550.       workInProgress = next;
    
  2551.       return;
    
  2552.     }
    
  2553. 
    
  2554.     const siblingFiber = completedWork.sibling;
    
  2555.     if (siblingFiber !== null) {
    
  2556.       // If there is more work to do in this returnFiber, do that next.
    
  2557.       workInProgress = siblingFiber;
    
  2558.       return;
    
  2559.     }
    
  2560.     // Otherwise, return to the parent
    
  2561.     // $FlowFixMe[incompatible-type] we bail out when we get a null
    
  2562.     completedWork = returnFiber;
    
  2563.     // Update the next thing we're working on in case something throws.
    
  2564.     workInProgress = completedWork;
    
  2565.   } while (completedWork !== null);
    
  2566. 
    
  2567.   // We've reached the root.
    
  2568.   if (workInProgressRootExitStatus === RootInProgress) {
    
  2569.     workInProgressRootExitStatus = RootCompleted;
    
  2570.   }
    
  2571. }
    
  2572. 
    
  2573. function unwindUnitOfWork(unitOfWork: Fiber): void {
    
  2574.   let incompleteWork: Fiber = unitOfWork;
    
  2575.   do {
    
  2576.     // The current, flushed, state of this fiber is the alternate. Ideally
    
  2577.     // nothing should rely on this, but relying on it here means that we don't
    
  2578.     // need an additional field on the work in progress.
    
  2579.     const current = incompleteWork.alternate;
    
  2580. 
    
  2581.     // This fiber did not complete because something threw. Pop values off
    
  2582.     // the stack without entering the complete phase. If this is a boundary,
    
  2583.     // capture values if possible.
    
  2584.     const next = unwindWork(current, incompleteWork, entangledRenderLanes);
    
  2585. 
    
  2586.     // Because this fiber did not complete, don't reset its lanes.
    
  2587. 
    
  2588.     if (next !== null) {
    
  2589.       // Found a boundary that can handle this exception. Re-renter the
    
  2590.       // begin phase. This branch will return us to the normal work loop.
    
  2591.       //
    
  2592.       // Since we're restarting, remove anything that is not a host effect
    
  2593.       // from the effect tag.
    
  2594.       next.flags &= HostEffectMask;
    
  2595.       workInProgress = next;
    
  2596.       return;
    
  2597.     }
    
  2598. 
    
  2599.     // Keep unwinding until we reach either a boundary or the root.
    
  2600. 
    
  2601.     if (enableProfilerTimer && (incompleteWork.mode & ProfileMode) !== NoMode) {
    
  2602.       // Record the render duration for the fiber that errored.
    
  2603.       stopProfilerTimerIfRunningAndRecordDelta(incompleteWork, false);
    
  2604. 
    
  2605.       // Include the time spent working on failed children before continuing.
    
  2606.       let actualDuration = incompleteWork.actualDuration;
    
  2607.       let child = incompleteWork.child;
    
  2608.       while (child !== null) {
    
  2609.         // $FlowFixMe[unsafe-addition] addition with possible null/undefined value
    
  2610.         actualDuration += child.actualDuration;
    
  2611.         child = child.sibling;
    
  2612.       }
    
  2613.       incompleteWork.actualDuration = actualDuration;
    
  2614.     }
    
  2615. 
    
  2616.     // TODO: Once we stop prerendering siblings, instead of resetting the parent
    
  2617.     // of the node being unwound, we should be able to reset node itself as we
    
  2618.     // unwind the stack. Saves an additional null check.
    
  2619.     const returnFiber = incompleteWork.return;
    
  2620.     if (returnFiber !== null) {
    
  2621.       // Mark the parent fiber as incomplete and clear its subtree flags.
    
  2622.       // TODO: Once we stop prerendering siblings, we may be able to get rid of
    
  2623.       // the Incomplete flag because unwinding to the nearest boundary will
    
  2624.       // happen synchronously.
    
  2625.       returnFiber.flags |= Incomplete;
    
  2626.       returnFiber.subtreeFlags = NoFlags;
    
  2627.       returnFiber.deletions = null;
    
  2628.     }
    
  2629. 
    
  2630.     // NOTE: If we re-enable sibling prerendering in some cases, here we
    
  2631.     // would switch to the normal completion path: check if a sibling
    
  2632.     // exists, and if so, begin work on it.
    
  2633. 
    
  2634.     // Otherwise, return to the parent
    
  2635.     // $FlowFixMe[incompatible-type] we bail out when we get a null
    
  2636.     incompleteWork = returnFiber;
    
  2637.     // Update the next thing we're working on in case something throws.
    
  2638.     workInProgress = incompleteWork;
    
  2639.   } while (incompleteWork !== null);
    
  2640. 
    
  2641.   // We've unwound all the way to the root.
    
  2642.   workInProgressRootExitStatus = RootDidNotComplete;
    
  2643.   workInProgress = null;
    
  2644. }
    
  2645. 
    
  2646. function commitRoot(
    
  2647.   root: FiberRoot,
    
  2648.   recoverableErrors: null | Array<CapturedValue<mixed>>,
    
  2649.   transitions: Array<Transition> | null,
    
  2650.   spawnedLane: Lane,
    
  2651. ) {
    
  2652.   // TODO: This no longer makes any sense. We already wrap the mutation and
    
  2653.   // layout phases. Should be able to remove.
    
  2654.   const previousUpdateLanePriority = getCurrentUpdatePriority();
    
  2655.   const prevTransition = ReactCurrentBatchConfig.transition;
    
  2656. 
    
  2657.   try {
    
  2658.     ReactCurrentBatchConfig.transition = null;
    
  2659.     setCurrentUpdatePriority(DiscreteEventPriority);
    
  2660.     commitRootImpl(
    
  2661.       root,
    
  2662.       recoverableErrors,
    
  2663.       transitions,
    
  2664.       previousUpdateLanePriority,
    
  2665.       spawnedLane,
    
  2666.     );
    
  2667.   } finally {
    
  2668.     ReactCurrentBatchConfig.transition = prevTransition;
    
  2669.     setCurrentUpdatePriority(previousUpdateLanePriority);
    
  2670.   }
    
  2671. 
    
  2672.   return null;
    
  2673. }
    
  2674. 
    
  2675. function commitRootImpl(
    
  2676.   root: FiberRoot,
    
  2677.   recoverableErrors: null | Array<CapturedValue<mixed>>,
    
  2678.   transitions: Array<Transition> | null,
    
  2679.   renderPriorityLevel: EventPriority,
    
  2680.   spawnedLane: Lane,
    
  2681. ) {
    
  2682.   do {
    
  2683.     // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which
    
  2684.     // means `flushPassiveEffects` will sometimes result in additional
    
  2685.     // passive effects. So we need to keep flushing in a loop until there are
    
  2686.     // no more pending effects.
    
  2687.     // TODO: Might be better if `flushPassiveEffects` did not automatically
    
  2688.     // flush synchronous work at the end, to avoid factoring hazards like this.
    
  2689.     flushPassiveEffects();
    
  2690.   } while (rootWithPendingPassiveEffects !== null);
    
  2691.   flushRenderPhaseStrictModeWarningsInDEV();
    
  2692. 
    
  2693.   if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
    
  2694.     throw new Error('Should not already be working.');
    
  2695.   }
    
  2696. 
    
  2697.   const finishedWork = root.finishedWork;
    
  2698.   const lanes = root.finishedLanes;
    
  2699. 
    
  2700.   if (__DEV__) {
    
  2701.     if (enableDebugTracing) {
    
  2702.       logCommitStarted(lanes);
    
  2703.     }
    
  2704.   }
    
  2705. 
    
  2706.   if (enableSchedulingProfiler) {
    
  2707.     markCommitStarted(lanes);
    
  2708.   }
    
  2709. 
    
  2710.   if (finishedWork === null) {
    
  2711.     if (__DEV__) {
    
  2712.       if (enableDebugTracing) {
    
  2713.         logCommitStopped();
    
  2714.       }
    
  2715.     }
    
  2716. 
    
  2717.     if (enableSchedulingProfiler) {
    
  2718.       markCommitStopped();
    
  2719.     }
    
  2720. 
    
  2721.     return null;
    
  2722.   } else {
    
  2723.     if (__DEV__) {
    
  2724.       if (lanes === NoLanes) {
    
  2725.         console.error(
    
  2726.           'root.finishedLanes should not be empty during a commit. This is a ' +
    
  2727.             'bug in React.',
    
  2728.         );
    
  2729.       }
    
  2730.     }
    
  2731.   }
    
  2732.   root.finishedWork = null;
    
  2733.   root.finishedLanes = NoLanes;
    
  2734. 
    
  2735.   if (finishedWork === root.current) {
    
  2736.     throw new Error(
    
  2737.       'Cannot commit the same tree as before. This error is likely caused by ' +
    
  2738.         'a bug in React. Please file an issue.',
    
  2739.     );
    
  2740.   }
    
  2741. 
    
  2742.   // commitRoot never returns a continuation; it always finishes synchronously.
    
  2743.   // So we can clear these now to allow a new callback to be scheduled.
    
  2744.   root.callbackNode = null;
    
  2745.   root.callbackPriority = NoLane;
    
  2746.   root.cancelPendingCommit = null;
    
  2747. 
    
  2748.   // Check which lanes no longer have any work scheduled on them, and mark
    
  2749.   // those as finished.
    
  2750.   let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
    
  2751. 
    
  2752.   // Make sure to account for lanes that were updated by a concurrent event
    
  2753.   // during the render phase; don't mark them as finished.
    
  2754.   const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();
    
  2755.   remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes);
    
  2756. 
    
  2757.   markRootFinished(root, remainingLanes, spawnedLane);
    
  2758. 
    
  2759.   if (root === workInProgressRoot) {
    
  2760.     // We can reset these now that they are finished.
    
  2761.     workInProgressRoot = null;
    
  2762.     workInProgress = null;
    
  2763.     workInProgressRootRenderLanes = NoLanes;
    
  2764.   } else {
    
  2765.     // This indicates that the last root we worked on is not the same one that
    
  2766.     // we're committing now. This most commonly happens when a suspended root
    
  2767.     // times out.
    
  2768.   }
    
  2769. 
    
  2770.   // If there are pending passive effects, schedule a callback to process them.
    
  2771.   // Do this as early as possible, so it is queued before anything else that
    
  2772.   // might get scheduled in the commit phase. (See #16714.)
    
  2773.   // TODO: Delete all other places that schedule the passive effect callback
    
  2774.   // They're redundant.
    
  2775.   if (
    
  2776.     (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||
    
  2777.     (finishedWork.flags & PassiveMask) !== NoFlags
    
  2778.   ) {
    
  2779.     if (!rootDoesHavePassiveEffects) {
    
  2780.       rootDoesHavePassiveEffects = true;
    
  2781.       pendingPassiveEffectsRemainingLanes = remainingLanes;
    
  2782.       // workInProgressTransitions might be overwritten, so we want
    
  2783.       // to store it in pendingPassiveTransitions until they get processed
    
  2784.       // We need to pass this through as an argument to commitRoot
    
  2785.       // because workInProgressTransitions might have changed between
    
  2786.       // the previous render and commit if we throttle the commit
    
  2787.       // with setTimeout
    
  2788.       pendingPassiveTransitions = transitions;
    
  2789.       scheduleCallback(NormalSchedulerPriority, () => {
    
  2790.         flushPassiveEffects();
    
  2791.         // This render triggered passive effects: release the root cache pool
    
  2792.         // *after* passive effects fire to avoid freeing a cache pool that may
    
  2793.         // be referenced by a node in the tree (HostRoot, Cache boundary etc)
    
  2794.         return null;
    
  2795.       });
    
  2796.     }
    
  2797.   }
    
  2798. 
    
  2799.   // Check if there are any effects in the whole tree.
    
  2800.   // TODO: This is left over from the effect list implementation, where we had
    
  2801.   // to check for the existence of `firstEffect` to satisfy Flow. I think the
    
  2802.   // only other reason this optimization exists is because it affects profiling.
    
  2803.   // Reconsider whether this is necessary.
    
  2804.   const subtreeHasEffects =
    
  2805.     (finishedWork.subtreeFlags &
    
  2806.       (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
    
  2807.     NoFlags;
    
  2808.   const rootHasEffect =
    
  2809.     (finishedWork.flags &
    
  2810.       (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
    
  2811.     NoFlags;
    
  2812. 
    
  2813.   if (subtreeHasEffects || rootHasEffect) {
    
  2814.     const prevTransition = ReactCurrentBatchConfig.transition;
    
  2815.     ReactCurrentBatchConfig.transition = null;
    
  2816.     const previousPriority = getCurrentUpdatePriority();
    
  2817.     setCurrentUpdatePriority(DiscreteEventPriority);
    
  2818. 
    
  2819.     const prevExecutionContext = executionContext;
    
  2820.     executionContext |= CommitContext;
    
  2821. 
    
  2822.     // Reset this to null before calling lifecycles
    
  2823.     ReactCurrentOwner.current = null;
    
  2824. 
    
  2825.     // The commit phase is broken into several sub-phases. We do a separate pass
    
  2826.     // of the effect list for each phase: all mutation effects come before all
    
  2827.     // layout effects, and so on.
    
  2828. 
    
  2829.     // The first phase a "before mutation" phase. We use this phase to read the
    
  2830.     // state of the host tree right before we mutate it. This is where
    
  2831.     // getSnapshotBeforeUpdate is called.
    
  2832.     const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(
    
  2833.       root,
    
  2834.       finishedWork,
    
  2835.     );
    
  2836. 
    
  2837.     if (enableProfilerTimer) {
    
  2838.       // Mark the current commit time to be shared by all Profilers in this
    
  2839.       // batch. This enables them to be grouped later.
    
  2840.       recordCommitTime();
    
  2841.     }
    
  2842. 
    
  2843.     if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {
    
  2844.       // Track the root here, rather than in commitLayoutEffects(), because of ref setters.
    
  2845.       // Updates scheduled during ref detachment should also be flagged.
    
  2846.       rootCommittingMutationOrLayoutEffects = root;
    
  2847.     }
    
  2848. 
    
  2849.     // The next phase is the mutation phase, where we mutate the host tree.
    
  2850.     commitMutationEffects(root, finishedWork, lanes);
    
  2851. 
    
  2852.     if (enableCreateEventHandleAPI) {
    
  2853.       if (shouldFireAfterActiveInstanceBlur) {
    
  2854.         afterActiveInstanceBlur();
    
  2855.       }
    
  2856.     }
    
  2857.     resetAfterCommit(root.containerInfo);
    
  2858. 
    
  2859.     // The work-in-progress tree is now the current tree. This must come after
    
  2860.     // the mutation phase, so that the previous tree is still current during
    
  2861.     // componentWillUnmount, but before the layout phase, so that the finished
    
  2862.     // work is current during componentDidMount/Update.
    
  2863.     root.current = finishedWork;
    
  2864. 
    
  2865.     // The next phase is the layout phase, where we call effects that read
    
  2866.     // the host tree after it's been mutated. The idiomatic use case for this is
    
  2867.     // layout, but class component lifecycles also fire here for legacy reasons.
    
  2868.     if (__DEV__) {
    
  2869.       if (enableDebugTracing) {
    
  2870.         logLayoutEffectsStarted(lanes);
    
  2871.       }
    
  2872.     }
    
  2873.     if (enableSchedulingProfiler) {
    
  2874.       markLayoutEffectsStarted(lanes);
    
  2875.     }
    
  2876.     commitLayoutEffects(finishedWork, root, lanes);
    
  2877.     if (__DEV__) {
    
  2878.       if (enableDebugTracing) {
    
  2879.         logLayoutEffectsStopped();
    
  2880.       }
    
  2881.     }
    
  2882. 
    
  2883.     if (enableSchedulingProfiler) {
    
  2884.       markLayoutEffectsStopped();
    
  2885.     }
    
  2886. 
    
  2887.     if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {
    
  2888.       rootCommittingMutationOrLayoutEffects = null;
    
  2889.     }
    
  2890. 
    
  2891.     // Tell Scheduler to yield at the end of the frame, so the browser has an
    
  2892.     // opportunity to paint.
    
  2893.     requestPaint();
    
  2894. 
    
  2895.     executionContext = prevExecutionContext;
    
  2896. 
    
  2897.     // Reset the priority to the previous non-sync value.
    
  2898.     setCurrentUpdatePriority(previousPriority);
    
  2899.     ReactCurrentBatchConfig.transition = prevTransition;
    
  2900.   } else {
    
  2901.     // No effects.
    
  2902.     root.current = finishedWork;
    
  2903.     // Measure these anyway so the flamegraph explicitly shows that there were
    
  2904.     // no effects.
    
  2905.     // TODO: Maybe there's a better way to report this.
    
  2906.     if (enableProfilerTimer) {
    
  2907.       recordCommitTime();
    
  2908.     }
    
  2909.   }
    
  2910. 
    
  2911.   const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;
    
  2912. 
    
  2913.   if (rootDoesHavePassiveEffects) {
    
  2914.     // This commit has passive effects. Stash a reference to them. But don't
    
  2915.     // schedule a callback until after flushing layout work.
    
  2916.     rootDoesHavePassiveEffects = false;
    
  2917.     rootWithPendingPassiveEffects = root;
    
  2918.     pendingPassiveEffectsLanes = lanes;
    
  2919.   } else {
    
  2920.     // There were no passive effects, so we can immediately release the cache
    
  2921.     // pool for this render.
    
  2922.     releaseRootPooledCache(root, remainingLanes);
    
  2923.     if (__DEV__) {
    
  2924.       nestedPassiveUpdateCount = 0;
    
  2925.       rootWithPassiveNestedUpdates = null;
    
  2926.     }
    
  2927.   }
    
  2928. 
    
  2929.   // Read this again, since an effect might have updated it
    
  2930.   remainingLanes = root.pendingLanes;
    
  2931. 
    
  2932.   // Check if there's remaining work on this root
    
  2933.   // TODO: This is part of the `componentDidCatch` implementation. Its purpose
    
  2934.   // is to detect whether something might have called setState inside
    
  2935.   // `componentDidCatch`. The mechanism is known to be flawed because `setState`
    
  2936.   // inside `componentDidCatch` is itself flawed — that's why we recommend
    
  2937.   // `getDerivedStateFromError` instead. However, it could be improved by
    
  2938.   // checking if remainingLanes includes Sync work, instead of whether there's
    
  2939.   // any work remaining at all (which would also include stuff like Suspense
    
  2940.   // retries or transitions). It's been like this for a while, though, so fixing
    
  2941.   // it probably isn't that urgent.
    
  2942.   if (remainingLanes === NoLanes) {
    
  2943.     // If there's no remaining work, we can clear the set of already failed
    
  2944.     // error boundaries.
    
  2945.     legacyErrorBoundariesThatAlreadyFailed = null;
    
  2946.   }
    
  2947. 
    
  2948.   if (__DEV__) {
    
  2949.     if (!rootDidHavePassiveEffects) {
    
  2950.       commitDoubleInvokeEffectsInDEV(root, false);
    
  2951.     }
    
  2952.   }
    
  2953. 
    
  2954.   onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);
    
  2955. 
    
  2956.   if (enableUpdaterTracking) {
    
  2957.     if (isDevToolsPresent) {
    
  2958.       root.memoizedUpdaters.clear();
    
  2959.     }
    
  2960.   }
    
  2961. 
    
  2962.   if (__DEV__) {
    
  2963.     onCommitRootTestSelector();
    
  2964.   }
    
  2965. 
    
  2966.   // Always call this before exiting `commitRoot`, to ensure that any
    
  2967.   // additional work on this root is scheduled.
    
  2968.   ensureRootIsScheduled(root);
    
  2969. 
    
  2970.   if (recoverableErrors !== null) {
    
  2971.     // There were errors during this render, but recovered from them without
    
  2972.     // needing to surface it to the UI. We log them here.
    
  2973.     const onRecoverableError = root.onRecoverableError;
    
  2974.     for (let i = 0; i < recoverableErrors.length; i++) {
    
  2975.       const recoverableError = recoverableErrors[i];
    
  2976.       const errorInfo = makeErrorInfo(
    
  2977.         recoverableError.digest,
    
  2978.         recoverableError.stack,
    
  2979.       );
    
  2980.       onRecoverableError(recoverableError.value, errorInfo);
    
  2981.     }
    
  2982.   }
    
  2983. 
    
  2984.   if (hasUncaughtError) {
    
  2985.     hasUncaughtError = false;
    
  2986.     const error = firstUncaughtError;
    
  2987.     firstUncaughtError = null;
    
  2988.     throw error;
    
  2989.   }
    
  2990. 
    
  2991.   // If the passive effects are the result of a discrete render, flush them
    
  2992.   // synchronously at the end of the current task so that the result is
    
  2993.   // immediately observable. Otherwise, we assume that they are not
    
  2994.   // order-dependent and do not need to be observed by external systems, so we
    
  2995.   // can wait until after paint.
    
  2996.   // TODO: We can optimize this by not scheduling the callback earlier. Since we
    
  2997.   // currently schedule the callback in multiple places, will wait until those
    
  2998.   // are consolidated.
    
  2999.   if (includesSyncLane(pendingPassiveEffectsLanes) && root.tag !== LegacyRoot) {
    
  3000.     flushPassiveEffects();
    
  3001.   }
    
  3002. 
    
  3003.   // Read this again, since a passive effect might have updated it
    
  3004.   remainingLanes = root.pendingLanes;
    
  3005. 
    
  3006.   // Check if this render scheduled a cascading synchronous update. This is a
    
  3007.   // heurstic to detect infinite update loops. We are intentionally excluding
    
  3008.   // hydration lanes in this check, because render triggered by selective
    
  3009.   // hydration is conceptually not an update.
    
  3010.   if (
    
  3011.     // Was the finished render the result of an update (not hydration)?
    
  3012.     includesSomeLane(lanes, UpdateLanes) &&
    
  3013.     // Did it schedule a sync update?
    
  3014.     includesSomeLane(remainingLanes, SyncUpdateLanes)
    
  3015.   ) {
    
  3016.     if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
    
  3017.       markNestedUpdateScheduled();
    
  3018.     }
    
  3019. 
    
  3020.     // Count the number of times the root synchronously re-renders without
    
  3021.     // finishing. If there are too many, it indicates an infinite update loop.
    
  3022.     if (root === rootWithNestedUpdates) {
    
  3023.       nestedUpdateCount++;
    
  3024.     } else {
    
  3025.       nestedUpdateCount = 0;
    
  3026.       rootWithNestedUpdates = root;
    
  3027.     }
    
  3028.   } else {
    
  3029.     nestedUpdateCount = 0;
    
  3030.   }
    
  3031. 
    
  3032.   // If layout work was scheduled, flush it now.
    
  3033.   flushSyncWorkOnAllRoots();
    
  3034. 
    
  3035.   if (__DEV__) {
    
  3036.     if (enableDebugTracing) {
    
  3037.       logCommitStopped();
    
  3038.     }
    
  3039.   }
    
  3040. 
    
  3041.   if (enableSchedulingProfiler) {
    
  3042.     markCommitStopped();
    
  3043.   }
    
  3044. 
    
  3045.   if (enableTransitionTracing) {
    
  3046.     // We process transitions during passive effects. However, passive effects can be
    
  3047.     // processed synchronously during the commit phase as well as asynchronously after
    
  3048.     // paint. At the end of the commit phase, we schedule a callback that will be called
    
  3049.     // after the next paint. If the transitions have already been processed (passive
    
  3050.     // effect phase happened synchronously), we will schedule a callback to process
    
  3051.     // the transitions. However, if we don't have any pending transition callbacks, this
    
  3052.     // means that the transitions have yet to be processed (passive effects processed after paint)
    
  3053.     // so we will store the end time of paint so that we can process the transitions
    
  3054.     // and then call the callback via the correct end time.
    
  3055.     const prevRootTransitionCallbacks = root.transitionCallbacks;
    
  3056.     if (prevRootTransitionCallbacks !== null) {
    
  3057.       schedulePostPaintCallback(endTime => {
    
  3058.         const prevPendingTransitionCallbacks =
    
  3059.           currentPendingTransitionCallbacks;
    
  3060.         if (prevPendingTransitionCallbacks !== null) {
    
  3061.           currentPendingTransitionCallbacks = null;
    
  3062.           scheduleCallback(IdleSchedulerPriority, () => {
    
  3063.             processTransitionCallbacks(
    
  3064.               prevPendingTransitionCallbacks,
    
  3065.               endTime,
    
  3066.               prevRootTransitionCallbacks,
    
  3067.             );
    
  3068.           });
    
  3069.         } else {
    
  3070.           currentEndTime = endTime;
    
  3071.         }
    
  3072.       });
    
  3073.     }
    
  3074.   }
    
  3075. 
    
  3076.   return null;
    
  3077. }
    
  3078. 
    
  3079. function makeErrorInfo(digest: ?string, componentStack: ?string) {
    
  3080.   if (__DEV__) {
    
  3081.     const errorInfo = {
    
  3082.       componentStack,
    
  3083.       digest,
    
  3084.     };
    
  3085.     Object.defineProperty(errorInfo, 'digest', {
    
  3086.       configurable: false,
    
  3087.       enumerable: true,
    
  3088.       get() {
    
  3089.         console.error(
    
  3090.           'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' +
    
  3091.             ' This property is deprecated and will be removed in a future version of React.' +
    
  3092.             ' To access the digest of an Error look for this property on the Error instance itself.',
    
  3093.         );
    
  3094.         return digest;
    
  3095.       },
    
  3096.     });
    
  3097.     return errorInfo;
    
  3098.   } else {
    
  3099.     return {
    
  3100.       digest,
    
  3101.       componentStack,
    
  3102.     };
    
  3103.   }
    
  3104. }
    
  3105. 
    
  3106. function releaseRootPooledCache(root: FiberRoot, remainingLanes: Lanes) {
    
  3107.   if (enableCache) {
    
  3108.     const pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes);
    
  3109.     if (pooledCacheLanes === NoLanes) {
    
  3110.       // None of the remaining work relies on the cache pool. Clear it so
    
  3111.       // subsequent requests get a new cache
    
  3112.       const pooledCache = root.pooledCache;
    
  3113.       if (pooledCache != null) {
    
  3114.         root.pooledCache = null;
    
  3115.         releaseCache(pooledCache);
    
  3116.       }
    
  3117.     }
    
  3118.   }
    
  3119. }
    
  3120. 
    
  3121. export function flushPassiveEffects(): boolean {
    
  3122.   // Returns whether passive effects were flushed.
    
  3123.   // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should
    
  3124.   // probably just combine the two functions. I believe they were only separate
    
  3125.   // in the first place because we used to wrap it with
    
  3126.   // `Scheduler.runWithPriority`, which accepts a function. But now we track the
    
  3127.   // priority within React itself, so we can mutate the variable directly.
    
  3128.   if (rootWithPendingPassiveEffects !== null) {
    
  3129.     // Cache the root since rootWithPendingPassiveEffects is cleared in
    
  3130.     // flushPassiveEffectsImpl
    
  3131.     const root = rootWithPendingPassiveEffects;
    
  3132.     // Cache and clear the remaining lanes flag; it must be reset since this
    
  3133.     // method can be called from various places, not always from commitRoot
    
  3134.     // where the remaining lanes are known
    
  3135.     const remainingLanes = pendingPassiveEffectsRemainingLanes;
    
  3136.     pendingPassiveEffectsRemainingLanes = NoLanes;
    
  3137. 
    
  3138.     const renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes);
    
  3139.     const priority = lowerEventPriority(DefaultEventPriority, renderPriority);
    
  3140.     const prevTransition = ReactCurrentBatchConfig.transition;
    
  3141.     const previousPriority = getCurrentUpdatePriority();
    
  3142. 
    
  3143.     try {
    
  3144.       ReactCurrentBatchConfig.transition = null;
    
  3145.       setCurrentUpdatePriority(priority);
    
  3146.       return flushPassiveEffectsImpl();
    
  3147.     } finally {
    
  3148.       setCurrentUpdatePriority(previousPriority);
    
  3149.       ReactCurrentBatchConfig.transition = prevTransition;
    
  3150. 
    
  3151.       // Once passive effects have run for the tree - giving components a
    
  3152.       // chance to retain cache instances they use - release the pooled
    
  3153.       // cache at the root (if there is one)
    
  3154.       releaseRootPooledCache(root, remainingLanes);
    
  3155.     }
    
  3156.   }
    
  3157.   return false;
    
  3158. }
    
  3159. 
    
  3160. export function enqueuePendingPassiveProfilerEffect(fiber: Fiber): void {
    
  3161.   if (enableProfilerTimer && enableProfilerCommitHooks) {
    
  3162.     pendingPassiveProfilerEffects.push(fiber);
    
  3163.     if (!rootDoesHavePassiveEffects) {
    
  3164.       rootDoesHavePassiveEffects = true;
    
  3165.       scheduleCallback(NormalSchedulerPriority, () => {
    
  3166.         flushPassiveEffects();
    
  3167.         return null;
    
  3168.       });
    
  3169.     }
    
  3170.   }
    
  3171. }
    
  3172. 
    
  3173. function flushPassiveEffectsImpl() {
    
  3174.   if (rootWithPendingPassiveEffects === null) {
    
  3175.     return false;
    
  3176.   }
    
  3177. 
    
  3178.   // Cache and clear the transitions flag
    
  3179.   const transitions = pendingPassiveTransitions;
    
  3180.   pendingPassiveTransitions = null;
    
  3181. 
    
  3182.   const root = rootWithPendingPassiveEffects;
    
  3183.   const lanes = pendingPassiveEffectsLanes;
    
  3184.   rootWithPendingPassiveEffects = null;
    
  3185.   // TODO: This is sometimes out of sync with rootWithPendingPassiveEffects.
    
  3186.   // Figure out why and fix it. It's not causing any known issues (probably
    
  3187.   // because it's only used for profiling), but it's a refactor hazard.
    
  3188.   pendingPassiveEffectsLanes = NoLanes;
    
  3189. 
    
  3190.   if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
    
  3191.     throw new Error('Cannot flush passive effects while already rendering.');
    
  3192.   }
    
  3193. 
    
  3194.   if (__DEV__) {
    
  3195.     isFlushingPassiveEffects = true;
    
  3196.     didScheduleUpdateDuringPassiveEffects = false;
    
  3197. 
    
  3198.     if (enableDebugTracing) {
    
  3199.       logPassiveEffectsStarted(lanes);
    
  3200.     }
    
  3201.   }
    
  3202. 
    
  3203.   if (enableSchedulingProfiler) {
    
  3204.     markPassiveEffectsStarted(lanes);
    
  3205.   }
    
  3206. 
    
  3207.   const prevExecutionContext = executionContext;
    
  3208.   executionContext |= CommitContext;
    
  3209. 
    
  3210.   commitPassiveUnmountEffects(root.current);
    
  3211.   commitPassiveMountEffects(root, root.current, lanes, transitions);
    
  3212. 
    
  3213.   // TODO: Move to commitPassiveMountEffects
    
  3214.   if (enableProfilerTimer && enableProfilerCommitHooks) {
    
  3215.     const profilerEffects = pendingPassiveProfilerEffects;
    
  3216.     pendingPassiveProfilerEffects = [];
    
  3217.     for (let i = 0; i < profilerEffects.length; i++) {
    
  3218.       const fiber = ((profilerEffects[i]: any): Fiber);
    
  3219.       commitPassiveEffectDurations(root, fiber);
    
  3220.     }
    
  3221.   }
    
  3222. 
    
  3223.   if (__DEV__) {
    
  3224.     if (enableDebugTracing) {
    
  3225.       logPassiveEffectsStopped();
    
  3226.     }
    
  3227.   }
    
  3228. 
    
  3229.   if (enableSchedulingProfiler) {
    
  3230.     markPassiveEffectsStopped();
    
  3231.   }
    
  3232. 
    
  3233.   if (__DEV__) {
    
  3234.     commitDoubleInvokeEffectsInDEV(root, true);
    
  3235.   }
    
  3236. 
    
  3237.   executionContext = prevExecutionContext;
    
  3238. 
    
  3239.   flushSyncWorkOnAllRoots();
    
  3240. 
    
  3241.   if (enableTransitionTracing) {
    
  3242.     const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
    
  3243.     const prevRootTransitionCallbacks = root.transitionCallbacks;
    
  3244.     const prevEndTime = currentEndTime;
    
  3245.     if (
    
  3246.       prevPendingTransitionCallbacks !== null &&
    
  3247.       prevRootTransitionCallbacks !== null &&
    
  3248.       prevEndTime !== null
    
  3249.     ) {
    
  3250.       currentPendingTransitionCallbacks = null;
    
  3251.       currentEndTime = null;
    
  3252.       scheduleCallback(IdleSchedulerPriority, () => {
    
  3253.         processTransitionCallbacks(
    
  3254.           prevPendingTransitionCallbacks,
    
  3255.           prevEndTime,
    
  3256.           prevRootTransitionCallbacks,
    
  3257.         );
    
  3258.       });
    
  3259.     }
    
  3260.   }
    
  3261. 
    
  3262.   if (__DEV__) {
    
  3263.     // If additional passive effects were scheduled, increment a counter. If this
    
  3264.     // exceeds the limit, we'll fire a warning.
    
  3265.     if (didScheduleUpdateDuringPassiveEffects) {
    
  3266.       if (root === rootWithPassiveNestedUpdates) {
    
  3267.         nestedPassiveUpdateCount++;
    
  3268.       } else {
    
  3269.         nestedPassiveUpdateCount = 0;
    
  3270.         rootWithPassiveNestedUpdates = root;
    
  3271.       }
    
  3272.     } else {
    
  3273.       nestedPassiveUpdateCount = 0;
    
  3274.     }
    
  3275.     isFlushingPassiveEffects = false;
    
  3276.     didScheduleUpdateDuringPassiveEffects = false;
    
  3277.   }
    
  3278. 
    
  3279.   // TODO: Move to commitPassiveMountEffects
    
  3280.   onPostCommitRootDevTools(root);
    
  3281.   if (enableProfilerTimer && enableProfilerCommitHooks) {
    
  3282.     const stateNode = root.current.stateNode;
    
  3283.     stateNode.effectDuration = 0;
    
  3284.     stateNode.passiveEffectDuration = 0;
    
  3285.   }
    
  3286. 
    
  3287.   return true;
    
  3288. }
    
  3289. 
    
  3290. export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {
    
  3291.   return (
    
  3292.     legacyErrorBoundariesThatAlreadyFailed !== null &&
    
  3293.     legacyErrorBoundariesThatAlreadyFailed.has(instance)
    
  3294.   );
    
  3295. }
    
  3296. 
    
  3297. export function markLegacyErrorBoundaryAsFailed(instance: mixed) {
    
  3298.   if (legacyErrorBoundariesThatAlreadyFailed === null) {
    
  3299.     legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);
    
  3300.   } else {
    
  3301.     legacyErrorBoundariesThatAlreadyFailed.add(instance);
    
  3302.   }
    
  3303. }
    
  3304. 
    
  3305. function prepareToThrowUncaughtError(error: mixed) {
    
  3306.   if (!hasUncaughtError) {
    
  3307.     hasUncaughtError = true;
    
  3308.     firstUncaughtError = error;
    
  3309.   }
    
  3310. }
    
  3311. export const onUncaughtError = prepareToThrowUncaughtError;
    
  3312. 
    
  3313. function captureCommitPhaseErrorOnRoot(
    
  3314.   rootFiber: Fiber,
    
  3315.   sourceFiber: Fiber,
    
  3316.   error: mixed,
    
  3317. ) {
    
  3318.   const errorInfo = createCapturedValueAtFiber(error, sourceFiber);
    
  3319.   const update = createRootErrorUpdate(rootFiber, errorInfo, (SyncLane: Lane));
    
  3320.   const root = enqueueUpdate(rootFiber, update, (SyncLane: Lane));
    
  3321.   if (root !== null) {
    
  3322.     markRootUpdated(root, SyncLane);
    
  3323.     ensureRootIsScheduled(root);
    
  3324.   }
    
  3325. }
    
  3326. 
    
  3327. export function captureCommitPhaseError(
    
  3328.   sourceFiber: Fiber,
    
  3329.   nearestMountedAncestor: Fiber | null,
    
  3330.   error: mixed,
    
  3331. ) {
    
  3332.   if (__DEV__) {
    
  3333.     reportUncaughtErrorInDEV(error);
    
  3334.     setIsRunningInsertionEffect(false);
    
  3335.   }
    
  3336.   if (sourceFiber.tag === HostRoot) {
    
  3337.     // Error was thrown at the root. There is no parent, so the root
    
  3338.     // itself should capture it.
    
  3339.     captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);
    
  3340.     return;
    
  3341.   }
    
  3342. 
    
  3343.   let fiber = nearestMountedAncestor;
    
  3344.   while (fiber !== null) {
    
  3345.     if (fiber.tag === HostRoot) {
    
  3346.       captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);
    
  3347.       return;
    
  3348.     } else if (fiber.tag === ClassComponent) {
    
  3349.       const ctor = fiber.type;
    
  3350.       const instance = fiber.stateNode;
    
  3351.       if (
    
  3352.         typeof ctor.getDerivedStateFromError === 'function' ||
    
  3353.         (typeof instance.componentDidCatch === 'function' &&
    
  3354.           !isAlreadyFailedLegacyErrorBoundary(instance))
    
  3355.       ) {
    
  3356.         const errorInfo = createCapturedValueAtFiber(error, sourceFiber);
    
  3357.         const update = createClassErrorUpdate(
    
  3358.           fiber,
    
  3359.           errorInfo,
    
  3360.           (SyncLane: Lane),
    
  3361.         );
    
  3362.         const root = enqueueUpdate(fiber, update, (SyncLane: Lane));
    
  3363.         if (root !== null) {
    
  3364.           markRootUpdated(root, SyncLane);
    
  3365.           ensureRootIsScheduled(root);
    
  3366.         }
    
  3367.         return;
    
  3368.       }
    
  3369.     }
    
  3370.     fiber = fiber.return;
    
  3371.   }
    
  3372. 
    
  3373.   if (__DEV__) {
    
  3374.     console.error(
    
  3375.       'Internal React error: Attempted to capture a commit phase error ' +
    
  3376.         'inside a detached tree. This indicates a bug in React. Potential ' +
    
  3377.         'causes include deleting the same fiber more than once, committing an ' +
    
  3378.         'already-finished tree, or an inconsistent return pointer.\n\n' +
    
  3379.         'Error message:\n\n%s',
    
  3380.       error,
    
  3381.     );
    
  3382.   }
    
  3383. }
    
  3384. 
    
  3385. export function attachPingListener(
    
  3386.   root: FiberRoot,
    
  3387.   wakeable: Wakeable,
    
  3388.   lanes: Lanes,
    
  3389. ) {
    
  3390.   // Attach a ping listener
    
  3391.   //
    
  3392.   // The data might resolve before we have a chance to commit the fallback. Or,
    
  3393.   // in the case of a refresh, we'll never commit a fallback. So we need to
    
  3394.   // attach a listener now. When it resolves ("pings"), we can decide whether to
    
  3395.   // try rendering the tree again.
    
  3396.   //
    
  3397.   // Only attach a listener if one does not already exist for the lanes
    
  3398.   // we're currently rendering (which acts like a "thread ID" here).
    
  3399.   //
    
  3400.   // We only need to do this in concurrent mode. Legacy Suspense always
    
  3401.   // commits fallbacks synchronously, so there are no pings.
    
  3402.   let pingCache = root.pingCache;
    
  3403.   let threadIDs;
    
  3404.   if (pingCache === null) {
    
  3405.     pingCache = root.pingCache = new PossiblyWeakMap();
    
  3406.     threadIDs = new Set<mixed>();
    
  3407.     pingCache.set(wakeable, threadIDs);
    
  3408.   } else {
    
  3409.     threadIDs = pingCache.get(wakeable);
    
  3410.     if (threadIDs === undefined) {
    
  3411.       threadIDs = new Set();
    
  3412.       pingCache.set(wakeable, threadIDs);
    
  3413.     }
    
  3414.   }
    
  3415.   if (!threadIDs.has(lanes)) {
    
  3416.     workInProgressRootDidAttachPingListener = true;
    
  3417. 
    
  3418.     // Memoize using the thread ID to prevent redundant listeners.
    
  3419.     threadIDs.add(lanes);
    
  3420.     const ping = pingSuspendedRoot.bind(null, root, wakeable, lanes);
    
  3421.     if (enableUpdaterTracking) {
    
  3422.       if (isDevToolsPresent) {
    
  3423.         // If we have pending work still, restore the original updaters
    
  3424.         restorePendingUpdaters(root, lanes);
    
  3425.       }
    
  3426.     }
    
  3427.     wakeable.then(ping, ping);
    
  3428.   }
    
  3429. }
    
  3430. 
    
  3431. function pingSuspendedRoot(
    
  3432.   root: FiberRoot,
    
  3433.   wakeable: Wakeable,
    
  3434.   pingedLanes: Lanes,
    
  3435. ) {
    
  3436.   const pingCache = root.pingCache;
    
  3437.   if (pingCache !== null) {
    
  3438.     // The wakeable resolved, so we no longer need to memoize, because it will
    
  3439.     // never be thrown again.
    
  3440.     pingCache.delete(wakeable);
    
  3441.   }
    
  3442. 
    
  3443.   markRootPinged(root, pingedLanes);
    
  3444. 
    
  3445.   warnIfSuspenseResolutionNotWrappedWithActDEV(root);
    
  3446. 
    
  3447.   if (
    
  3448.     workInProgressRoot === root &&
    
  3449.     isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)
    
  3450.   ) {
    
  3451.     // Received a ping at the same priority level at which we're currently
    
  3452.     // rendering. We might want to restart this render. This should mirror
    
  3453.     // the logic of whether or not a root suspends once it completes.
    
  3454.     // TODO: If we're rendering sync either due to Sync, Batched or expired,
    
  3455.     // we should probably never restart.
    
  3456. 
    
  3457.     // If we're suspended with delay, or if it's a retry, we'll always suspend
    
  3458.     // so we can always restart.
    
  3459.     if (
    
  3460.       workInProgressRootExitStatus === RootSuspendedWithDelay ||
    
  3461.       (workInProgressRootExitStatus === RootSuspended &&
    
  3462.         includesOnlyRetries(workInProgressRootRenderLanes) &&
    
  3463.         now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)
    
  3464.     ) {
    
  3465.       // Force a restart from the root by unwinding the stack. Unless this is
    
  3466.       // being called from the render phase, because that would cause a crash.
    
  3467.       if ((executionContext & RenderContext) === NoContext) {
    
  3468.         prepareFreshStack(root, NoLanes);
    
  3469.       } else {
    
  3470.         // TODO: If this does happen during the render phase, we should throw
    
  3471.         // the special internal exception that we use to interrupt the stack for
    
  3472.         // selective hydration. That was temporarily reverted but we once we add
    
  3473.         // it back we can use it here.
    
  3474.       }
    
  3475.     } else {
    
  3476.       // Even though we can't restart right now, we might get an
    
  3477.       // opportunity later. So we mark this render as having a ping.
    
  3478.       workInProgressRootPingedLanes = mergeLanes(
    
  3479.         workInProgressRootPingedLanes,
    
  3480.         pingedLanes,
    
  3481.       );
    
  3482.     }
    
  3483.   }
    
  3484. 
    
  3485.   ensureRootIsScheduled(root);
    
  3486. }
    
  3487. 
    
  3488. function retryTimedOutBoundary(boundaryFiber: Fiber, retryLane: Lane) {
    
  3489.   // The boundary fiber (a Suspense component or SuspenseList component)
    
  3490.   // previously was rendered in its fallback state. One of the promises that
    
  3491.   // suspended it has resolved, which means at least part of the tree was
    
  3492.   // likely unblocked. Try rendering again, at a new lanes.
    
  3493.   if (retryLane === NoLane) {
    
  3494.     // TODO: Assign this to `suspenseState.retryLane`? to avoid
    
  3495.     // unnecessary entanglement?
    
  3496.     retryLane = requestRetryLane(boundaryFiber);
    
  3497.   }
    
  3498.   // TODO: Special case idle priority?
    
  3499.   const root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane);
    
  3500.   if (root !== null) {
    
  3501.     markRootUpdated(root, retryLane);
    
  3502.     ensureRootIsScheduled(root);
    
  3503.   }
    
  3504. }
    
  3505. 
    
  3506. export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {
    
  3507.   const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
    
  3508.   let retryLane = NoLane;
    
  3509.   if (suspenseState !== null) {
    
  3510.     retryLane = suspenseState.retryLane;
    
  3511.   }
    
  3512.   retryTimedOutBoundary(boundaryFiber, retryLane);
    
  3513. }
    
  3514. 
    
  3515. export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {
    
  3516.   let retryLane = NoLane; // Default
    
  3517.   let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;
    
  3518.   switch (boundaryFiber.tag) {
    
  3519.     case SuspenseComponent:
    
  3520.       retryCache = boundaryFiber.stateNode;
    
  3521.       const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
    
  3522.       if (suspenseState !== null) {
    
  3523.         retryLane = suspenseState.retryLane;
    
  3524.       }
    
  3525.       break;
    
  3526.     case SuspenseListComponent:
    
  3527.       retryCache = boundaryFiber.stateNode;
    
  3528.       break;
    
  3529.     case OffscreenComponent: {
    
  3530.       const instance: OffscreenInstance = boundaryFiber.stateNode;
    
  3531.       retryCache = instance._retryCache;
    
  3532.       break;
    
  3533.     }
    
  3534.     default:
    
  3535.       throw new Error(
    
  3536.         'Pinged unknown suspense boundary type. ' +
    
  3537.           'This is probably a bug in React.',
    
  3538.       );
    
  3539.   }
    
  3540. 
    
  3541.   if (retryCache !== null) {
    
  3542.     // The wakeable resolved, so we no longer need to memoize, because it will
    
  3543.     // never be thrown again.
    
  3544.     retryCache.delete(wakeable);
    
  3545.   }
    
  3546. 
    
  3547.   retryTimedOutBoundary(boundaryFiber, retryLane);
    
  3548. }
    
  3549. 
    
  3550. export function throwIfInfiniteUpdateLoopDetected() {
    
  3551.   if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
    
  3552.     nestedUpdateCount = 0;
    
  3553.     nestedPassiveUpdateCount = 0;
    
  3554.     rootWithNestedUpdates = null;
    
  3555.     rootWithPassiveNestedUpdates = null;
    
  3556. 
    
  3557.     throw new Error(
    
  3558.       'Maximum update depth exceeded. This can happen when a component ' +
    
  3559.         'repeatedly calls setState inside componentWillUpdate or ' +
    
  3560.         'componentDidUpdate. React limits the number of nested updates to ' +
    
  3561.         'prevent infinite loops.',
    
  3562.     );
    
  3563.   }
    
  3564. 
    
  3565.   if (__DEV__) {
    
  3566.     if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {
    
  3567.       nestedPassiveUpdateCount = 0;
    
  3568.       rootWithPassiveNestedUpdates = null;
    
  3569. 
    
  3570.       console.error(
    
  3571.         'Maximum update depth exceeded. This can happen when a component ' +
    
  3572.           "calls setState inside useEffect, but useEffect either doesn't " +
    
  3573.           'have a dependency array, or one of the dependencies changes on ' +
    
  3574.           'every render.',
    
  3575.       );
    
  3576.     }
    
  3577.   }
    
  3578. }
    
  3579. 
    
  3580. function flushRenderPhaseStrictModeWarningsInDEV() {
    
  3581.   if (__DEV__) {
    
  3582.     ReactStrictModeWarnings.flushLegacyContextWarning();
    
  3583.     ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();
    
  3584.   }
    
  3585. }
    
  3586. 
    
  3587. function recursivelyTraverseAndDoubleInvokeEffectsInDEV(
    
  3588.   root: FiberRoot,
    
  3589.   parentFiber: Fiber,
    
  3590.   isInStrictMode: boolean,
    
  3591. ) {
    
  3592.   if ((parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === NoFlags) {
    
  3593.     // Parent's descendants have already had effects double invoked.
    
  3594.     // Early exit to avoid unnecessary tree traversal.
    
  3595.     return;
    
  3596.   }
    
  3597.   let child = parentFiber.child;
    
  3598.   while (child !== null) {
    
  3599.     doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode);
    
  3600.     child = child.sibling;
    
  3601.   }
    
  3602. }
    
  3603. 
    
  3604. // Unconditionally disconnects and connects passive and layout effects.
    
  3605. function doubleInvokeEffectsOnFiber(
    
  3606.   root: FiberRoot,
    
  3607.   fiber: Fiber,
    
  3608.   shouldDoubleInvokePassiveEffects: boolean = true,
    
  3609. ) {
    
  3610.   disappearLayoutEffects(fiber);
    
  3611.   if (shouldDoubleInvokePassiveEffects) {
    
  3612.     disconnectPassiveEffect(fiber);
    
  3613.   }
    
  3614.   reappearLayoutEffects(root, fiber.alternate, fiber, false);
    
  3615.   if (shouldDoubleInvokePassiveEffects) {
    
  3616.     reconnectPassiveEffects(root, fiber, NoLanes, null, false);
    
  3617.   }
    
  3618. }
    
  3619. 
    
  3620. function doubleInvokeEffectsInDEVIfNecessary(
    
  3621.   root: FiberRoot,
    
  3622.   fiber: Fiber,
    
  3623.   parentIsInStrictMode: boolean,
    
  3624. ) {
    
  3625.   const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE;
    
  3626.   const isInStrictMode = parentIsInStrictMode || isStrictModeFiber;
    
  3627. 
    
  3628.   // First case: the fiber **is not** of type OffscreenComponent. No
    
  3629.   // special rules apply to double invoking effects.
    
  3630.   if (fiber.tag !== OffscreenComponent) {
    
  3631.     if (fiber.flags & PlacementDEV) {
    
  3632.       setCurrentDebugFiberInDEV(fiber);
    
  3633.       if (isInStrictMode) {
    
  3634.         doubleInvokeEffectsOnFiber(
    
  3635.           root,
    
  3636.           fiber,
    
  3637.           (fiber.mode & NoStrictPassiveEffectsMode) === NoMode,
    
  3638.         );
    
  3639.       }
    
  3640.       resetCurrentDebugFiberInDEV();
    
  3641.     } else {
    
  3642.       recursivelyTraverseAndDoubleInvokeEffectsInDEV(
    
  3643.         root,
    
  3644.         fiber,
    
  3645.         isInStrictMode,
    
  3646.       );
    
  3647.     }
    
  3648.     return;
    
  3649.   }
    
  3650. 
    
  3651.   // Second case: the fiber **is** of type OffscreenComponent.
    
  3652.   // This branch contains cases specific to Offscreen.
    
  3653.   if (fiber.memoizedState === null) {
    
  3654.     // Only consider Offscreen that is visible.
    
  3655.     // TODO (Offscreen) Handle manual mode.
    
  3656.     setCurrentDebugFiberInDEV(fiber);
    
  3657.     if (isInStrictMode && fiber.flags & Visibility) {
    
  3658.       // Double invoke effects on Offscreen's subtree only
    
  3659.       // if it is visible and its visibility has changed.
    
  3660.       doubleInvokeEffectsOnFiber(root, fiber);
    
  3661.     } else if (fiber.subtreeFlags & PlacementDEV) {
    
  3662.       // Something in the subtree could have been suspended.
    
  3663.       // We need to continue traversal and find newly inserted fibers.
    
  3664.       recursivelyTraverseAndDoubleInvokeEffectsInDEV(
    
  3665.         root,
    
  3666.         fiber,
    
  3667.         isInStrictMode,
    
  3668.       );
    
  3669.     }
    
  3670.     resetCurrentDebugFiberInDEV();
    
  3671.   }
    
  3672. }
    
  3673. 
    
  3674. function commitDoubleInvokeEffectsInDEV(
    
  3675.   root: FiberRoot,
    
  3676.   hasPassiveEffects: boolean,
    
  3677. ) {
    
  3678.   if (__DEV__) {
    
  3679.     if (useModernStrictMode) {
    
  3680.       let doubleInvokeEffects = true;
    
  3681. 
    
  3682.       if (root.tag === LegacyRoot && !(root.current.mode & StrictLegacyMode)) {
    
  3683.         doubleInvokeEffects = false;
    
  3684.       }
    
  3685.       if (
    
  3686.         root.tag === ConcurrentRoot &&
    
  3687.         !(root.current.mode & (StrictLegacyMode | StrictEffectsMode))
    
  3688.       ) {
    
  3689.         doubleInvokeEffects = false;
    
  3690.       }
    
  3691.       recursivelyTraverseAndDoubleInvokeEffectsInDEV(
    
  3692.         root,
    
  3693.         root.current,
    
  3694.         doubleInvokeEffects,
    
  3695.       );
    
  3696.     } else {
    
  3697.       legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects);
    
  3698.     }
    
  3699.   }
    
  3700. }
    
  3701. 
    
  3702. function legacyCommitDoubleInvokeEffectsInDEV(
    
  3703.   fiber: Fiber,
    
  3704.   hasPassiveEffects: boolean,
    
  3705. ) {
    
  3706.   // TODO (StrictEffects) Should we set a marker on the root if it contains strict effects
    
  3707.   // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level.
    
  3708.   // Maybe not a big deal since this is DEV only behavior.
    
  3709. 
    
  3710.   setCurrentDebugFiberInDEV(fiber);
    
  3711.   invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);
    
  3712.   if (hasPassiveEffects) {
    
  3713.     invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV);
    
  3714.   }
    
  3715. 
    
  3716.   invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV);
    
  3717.   if (hasPassiveEffects) {
    
  3718.     invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);
    
  3719.   }
    
  3720.   resetCurrentDebugFiberInDEV();
    
  3721. }
    
  3722. 
    
  3723. function invokeEffectsInDev(
    
  3724.   firstChild: Fiber,
    
  3725.   fiberFlags: Flags,
    
  3726.   invokeEffectFn: (fiber: Fiber) => void,
    
  3727. ) {
    
  3728.   let current: null | Fiber = firstChild;
    
  3729.   let subtreeRoot = null;
    
  3730.   while (current != null) {
    
  3731.     const primarySubtreeFlag = current.subtreeFlags & fiberFlags;
    
  3732.     if (
    
  3733.       current !== subtreeRoot &&
    
  3734.       current.child != null &&
    
  3735.       primarySubtreeFlag !== NoFlags
    
  3736.     ) {
    
  3737.       current = current.child;
    
  3738.     } else {
    
  3739.       if ((current.flags & fiberFlags) !== NoFlags) {
    
  3740.         invokeEffectFn(current);
    
  3741.       }
    
  3742. 
    
  3743.       if (current.sibling !== null) {
    
  3744.         current = current.sibling;
    
  3745.       } else {
    
  3746.         current = subtreeRoot = current.return;
    
  3747.       }
    
  3748.     }
    
  3749.   }
    
  3750. }
    
  3751. 
    
  3752. let didWarnStateUpdateForNotYetMountedComponent: Set<string> | null = null;
    
  3753. export function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber: Fiber) {
    
  3754.   if (__DEV__) {
    
  3755.     if ((executionContext & RenderContext) !== NoContext) {
    
  3756.       // We let the other warning about render phase updates deal with this one.
    
  3757.       return;
    
  3758.     }
    
  3759. 
    
  3760.     if (!(fiber.mode & ConcurrentMode)) {
    
  3761.       return;
    
  3762.     }
    
  3763. 
    
  3764.     const tag = fiber.tag;
    
  3765.     if (
    
  3766.       tag !== IndeterminateComponent &&
    
  3767.       tag !== HostRoot &&
    
  3768.       tag !== ClassComponent &&
    
  3769.       tag !== FunctionComponent &&
    
  3770.       tag !== ForwardRef &&
    
  3771.       tag !== MemoComponent &&
    
  3772.       tag !== SimpleMemoComponent
    
  3773.     ) {
    
  3774.       // Only warn for user-defined components, not internal ones like Suspense.
    
  3775.       return;
    
  3776.     }
    
  3777. 
    
  3778.     // We show the whole stack but dedupe on the top component's name because
    
  3779.     // the problematic code almost always lies inside that component.
    
  3780.     const componentName = getComponentNameFromFiber(fiber) || 'ReactComponent';
    
  3781.     if (didWarnStateUpdateForNotYetMountedComponent !== null) {
    
  3782.       if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {
    
  3783.         return;
    
  3784.       }
    
  3785.       // $FlowFixMe[incompatible-use] found when upgrading Flow
    
  3786.       didWarnStateUpdateForNotYetMountedComponent.add(componentName);
    
  3787.     } else {
    
  3788.       didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);
    
  3789.     }
    
  3790. 
    
  3791.     const previousFiber = ReactCurrentFiberCurrent;
    
  3792.     try {
    
  3793.       setCurrentDebugFiberInDEV(fiber);
    
  3794.       console.error(
    
  3795.         "Can't perform a React state update on a component that hasn't mounted yet. " +
    
  3796.           'This indicates that you have a side-effect in your render function that ' +
    
  3797.           'asynchronously later calls tries to update the component. Move this work to ' +
    
  3798.           'useEffect instead.',
    
  3799.       );
    
  3800.     } finally {
    
  3801.       if (previousFiber) {
    
  3802.         setCurrentDebugFiberInDEV(fiber);
    
  3803.       } else {
    
  3804.         resetCurrentDebugFiberInDEV();
    
  3805.       }
    
  3806.     }
    
  3807.   }
    
  3808. }
    
  3809. 
    
  3810. let beginWork;
    
  3811. if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
    
  3812.   const dummyFiber = null;
    
  3813.   beginWork = (current: null | Fiber, unitOfWork: Fiber, lanes: Lanes) => {
    
  3814.     // If a component throws an error, we replay it again in a synchronously
    
  3815.     // dispatched event, so that the debugger will treat it as an uncaught
    
  3816.     // error See ReactErrorUtils for more information.
    
  3817. 
    
  3818.     // Before entering the begin phase, copy the work-in-progress onto a dummy
    
  3819.     // fiber. If beginWork throws, we'll use this to reset the state.
    
  3820.     const originalWorkInProgressCopy = assignFiberPropertiesInDEV(
    
  3821.       dummyFiber,
    
  3822.       unitOfWork,
    
  3823.     );
    
  3824.     try {
    
  3825.       return originalBeginWork(current, unitOfWork, lanes);
    
  3826.     } catch (originalError) {
    
  3827.       if (
    
  3828.         didSuspendOrErrorWhileHydratingDEV() ||
    
  3829.         originalError === SuspenseException ||
    
  3830.         originalError === SelectiveHydrationException ||
    
  3831.         (originalError !== null &&
    
  3832.           typeof originalError === 'object' &&
    
  3833.           typeof originalError.then === 'function')
    
  3834.       ) {
    
  3835.         // Don't replay promises.
    
  3836.         // Don't replay errors if we are hydrating and have already suspended or handled an error
    
  3837.         throw originalError;
    
  3838.       }
    
  3839. 
    
  3840.       // Don't reset current debug fiber, since we're about to work on the
    
  3841.       // same fiber again.
    
  3842. 
    
  3843.       // Unwind the failed stack frame
    
  3844.       resetSuspendedWorkLoopOnUnwind(unitOfWork);
    
  3845.       unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes);
    
  3846. 
    
  3847.       // Restore the original properties of the fiber.
    
  3848.       assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);
    
  3849. 
    
  3850.       if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {
    
  3851.         // Reset the profiler timer.
    
  3852.         startProfilerTimer(unitOfWork);
    
  3853.       }
    
  3854. 
    
  3855.       // Run beginWork again.
    
  3856.       invokeGuardedCallback(
    
  3857.         null,
    
  3858.         originalBeginWork,
    
  3859.         null,
    
  3860.         current,
    
  3861.         unitOfWork,
    
  3862.         lanes,
    
  3863.       );
    
  3864. 
    
  3865.       if (hasCaughtError()) {
    
  3866.         const replayError = clearCaughtError();
    
  3867.         if (
    
  3868.           typeof replayError === 'object' &&
    
  3869.           replayError !== null &&
    
  3870.           replayError._suppressLogging &&
    
  3871.           typeof originalError === 'object' &&
    
  3872.           originalError !== null &&
    
  3873.           !originalError._suppressLogging
    
  3874.         ) {
    
  3875.           // If suppressed, let the flag carry over to the original error which is the one we'll rethrow.
    
  3876.           originalError._suppressLogging = true;
    
  3877.         }
    
  3878.       }
    
  3879.       // We always throw the original error in case the second render pass is not idempotent.
    
  3880.       // This can happen if a memoized function or CommonJS module doesn't throw after first invocation.
    
  3881.       throw originalError;
    
  3882.     }
    
  3883.   };
    
  3884. } else {
    
  3885.   beginWork = originalBeginWork;
    
  3886. }
    
  3887. 
    
  3888. let didWarnAboutUpdateInRender = false;
    
  3889. let didWarnAboutUpdateInRenderForAnotherComponent;
    
  3890. if (__DEV__) {
    
  3891.   didWarnAboutUpdateInRenderForAnotherComponent = new Set<string>();
    
  3892. }
    
  3893. 
    
  3894. function warnAboutRenderPhaseUpdatesInDEV(fiber: Fiber) {
    
  3895.   if (__DEV__) {
    
  3896.     if (ReactCurrentDebugFiberIsRenderingInDEV) {
    
  3897.       switch (fiber.tag) {
    
  3898.         case FunctionComponent:
    
  3899.         case ForwardRef:
    
  3900.         case SimpleMemoComponent: {
    
  3901.           const renderingComponentName =
    
  3902.             (workInProgress && getComponentNameFromFiber(workInProgress)) ||
    
  3903.             'Unknown';
    
  3904.           // Dedupe by the rendering component because it's the one that needs to be fixed.
    
  3905.           const dedupeKey = renderingComponentName;
    
  3906.           if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {
    
  3907.             didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);
    
  3908.             const setStateComponentName =
    
  3909.               getComponentNameFromFiber(fiber) || 'Unknown';
    
  3910.             console.error(
    
  3911.               'Cannot update a component (`%s`) while rendering a ' +
    
  3912.                 'different component (`%s`). To locate the bad setState() call inside `%s`, ' +
    
  3913.                 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render',
    
  3914.               setStateComponentName,
    
  3915.               renderingComponentName,
    
  3916.               renderingComponentName,
    
  3917.             );
    
  3918.           }
    
  3919.           break;
    
  3920.         }
    
  3921.         case ClassComponent: {
    
  3922.           if (!didWarnAboutUpdateInRender) {
    
  3923.             console.error(
    
  3924.               'Cannot update during an existing state transition (such as ' +
    
  3925.                 'within `render`). Render methods should be a pure ' +
    
  3926.                 'function of props and state.',
    
  3927.             );
    
  3928.             didWarnAboutUpdateInRender = true;
    
  3929.           }
    
  3930.           break;
    
  3931.         }
    
  3932.       }
    
  3933.     }
    
  3934.   }
    
  3935. }
    
  3936. 
    
  3937. export function restorePendingUpdaters(root: FiberRoot, lanes: Lanes): void {
    
  3938.   if (enableUpdaterTracking) {
    
  3939.     if (isDevToolsPresent) {
    
  3940.       const memoizedUpdaters = root.memoizedUpdaters;
    
  3941.       memoizedUpdaters.forEach(schedulingFiber => {
    
  3942.         addFiberToLanesMap(root, schedulingFiber, lanes);
    
  3943.       });
    
  3944. 
    
  3945.       // This function intentionally does not clear memoized updaters.
    
  3946.       // Those may still be relevant to the current commit
    
  3947.       // and a future one (e.g. Suspense).
    
  3948.     }
    
  3949.   }
    
  3950. }
    
  3951. 
    
  3952. const fakeActCallbackNode = {};
    
  3953. // $FlowFixMe[missing-local-annot]
    
  3954. function scheduleCallback(priorityLevel: any, callback) {
    
  3955.   if (__DEV__) {
    
  3956.     // If we're currently inside an `act` scope, bypass Scheduler and push to
    
  3957.     // the `act` queue instead.
    
  3958.     const actQueue = ReactCurrentActQueue.current;
    
  3959.     if (actQueue !== null) {
    
  3960.       actQueue.push(callback);
    
  3961.       return fakeActCallbackNode;
    
  3962.     } else {
    
  3963.       return Scheduler_scheduleCallback(priorityLevel, callback);
    
  3964.     }
    
  3965.   } else {
    
  3966.     // In production, always call Scheduler. This function will be stripped out.
    
  3967.     return Scheduler_scheduleCallback(priorityLevel, callback);
    
  3968.   }
    
  3969. }
    
  3970. 
    
  3971. function shouldForceFlushFallbacksInDEV() {
    
  3972.   // Never force flush in production. This function should get stripped out.
    
  3973.   return __DEV__ && ReactCurrentActQueue.current !== null;
    
  3974. }
    
  3975. 
    
  3976. function warnIfUpdatesNotWrappedWithActDEV(fiber: Fiber): void {
    
  3977.   if (__DEV__) {
    
  3978.     if (fiber.mode & ConcurrentMode) {
    
  3979.       if (!isConcurrentActEnvironment()) {
    
  3980.         // Not in an act environment. No need to warn.
    
  3981.         return;
    
  3982.       }
    
  3983.     } else {
    
  3984.       // Legacy mode has additional cases where we suppress a warning.
    
  3985.       if (!isLegacyActEnvironment(fiber)) {
    
  3986.         // Not in an act environment. No need to warn.
    
  3987.         return;
    
  3988.       }
    
  3989.       if (executionContext !== NoContext) {
    
  3990.         // Legacy mode doesn't warn if the update is batched, i.e.
    
  3991.         // batchedUpdates or flushSync.
    
  3992.         return;
    
  3993.       }
    
  3994.       if (
    
  3995.         fiber.tag !== FunctionComponent &&
    
  3996.         fiber.tag !== ForwardRef &&
    
  3997.         fiber.tag !== SimpleMemoComponent
    
  3998.       ) {
    
  3999.         // For backwards compatibility with pre-hooks code, legacy mode only
    
  4000.         // warns for updates that originate from a hook.
    
  4001.         return;
    
  4002.       }
    
  4003.     }
    
  4004. 
    
  4005.     if (ReactCurrentActQueue.current === null) {
    
  4006.       const previousFiber = ReactCurrentFiberCurrent;
    
  4007.       try {
    
  4008.         setCurrentDebugFiberInDEV(fiber);
    
  4009.         console.error(
    
  4010.           'An update to %s inside a test was not wrapped in act(...).\n\n' +
    
  4011.             'When testing, code that causes React state updates should be ' +
    
  4012.             'wrapped into act(...):\n\n' +
    
  4013.             'act(() => {\n' +
    
  4014.             '  /* fire events that update state */\n' +
    
  4015.             '});\n' +
    
  4016.             '/* assert on the output */\n\n' +
    
  4017.             "This ensures that you're testing the behavior the user would see " +
    
  4018.             'in the browser.' +
    
  4019.             ' Learn more at https://reactjs.org/link/wrap-tests-with-act',
    
  4020.           getComponentNameFromFiber(fiber),
    
  4021.         );
    
  4022.       } finally {
    
  4023.         if (previousFiber) {
    
  4024.           setCurrentDebugFiberInDEV(fiber);
    
  4025.         } else {
    
  4026.           resetCurrentDebugFiberInDEV();
    
  4027.         }
    
  4028.       }
    
  4029.     }
    
  4030.   }
    
  4031. }
    
  4032. 
    
  4033. function warnIfSuspenseResolutionNotWrappedWithActDEV(root: FiberRoot): void {
    
  4034.   if (__DEV__) {
    
  4035.     if (
    
  4036.       root.tag !== LegacyRoot &&
    
  4037.       isConcurrentActEnvironment() &&
    
  4038.       ReactCurrentActQueue.current === null
    
  4039.     ) {
    
  4040.       console.error(
    
  4041.         'A suspended resource finished loading inside a test, but the event ' +
    
  4042.           'was not wrapped in act(...).\n\n' +
    
  4043.           'When testing, code that resolves suspended data should be wrapped ' +
    
  4044.           'into act(...):\n\n' +
    
  4045.           'act(() => {\n' +
    
  4046.           '  /* finish loading suspended data */\n' +
    
  4047.           '});\n' +
    
  4048.           '/* assert on the output */\n\n' +
    
  4049.           "This ensures that you're testing the behavior the user would see " +
    
  4050.           'in the browser.' +
    
  4051.           ' Learn more at https://reactjs.org/link/wrap-tests-with-act',
    
  4052.       );
    
  4053.     }
    
  4054.   }
    
  4055. }
    
  4056. 
    
  4057. export function setIsRunningInsertionEffect(isRunning: boolean): void {
    
  4058.   if (__DEV__) {
    
  4059.     isRunningInsertionEffect = isRunning;
    
  4060.   }
    
  4061. }