How to use popDispatcher method in Playwright Internal

Best JavaScript code snippet using playwright-internal

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

ReactFiberWorkLoop.js

Source: ReactFiberWorkLoop.js Github

copy
1import {
2  flushSyncCallbackQueue,
3  now,
4  getCurrentPriorityLevel,
5  ImmediatePriority as ImmediateSchedulerPriority,
6  UserBlockingPriority,
7  NoPriority as NoSchedulerPriority,
8  NormalPriority as NormalSchedulerPriority,
9  UserBlockingPriority as UserBlockingSchedulerPriority,
10  runWithPriority,
11  scheduleCallback,
12  cancelCallback,
13  scheduleSyncCallback,
14  requestPaint,
15} from './SchedulerWithReactIntegration';
16import {
17  NoTimestamp,
18  SyncLane,
19  SyncBatchedLane,
20  NoLanes,
21  findUpdateLane,
22  schedulerPriorityToLanePriority,
23  InputDiscreteLanePriority,
24  mergeLanes,
25  markRootUpdated,
26  markRootSuspended as markRootSuspendedDontCallThisOneDirectly,
27  includesSomeLane,
28  OffscreenLane,
29  getNextLanes,
30  markRootFinished,
31  hasDiscreteLanes,
32  markStarvedLanesAsExpired,
33  returnNextLanesPriority,
34  SyncLanePriority,
35  lanePriorityToSchedulerPriority,
36  SyncBatchedLanePriority,
37} from './ReactFiberLane';
38import { ConcurrentMode, BlockingMode, NoMode } from './ReactTypeOfMode';
39import { requestCurrentTransition, NoTransition } from './ReactFiberTransition';
40import { ContextOnlyDispatcher } from './ReactFiberHooks';
41import { unwindInterruptedWork, unwindWork } from './ReactFiberUnwindWork';
42import { createWorkInProgress } from './ReactFiber';
43import { beginWork } from './ReactFiberBeginWork';
44import {
45  NoFlags,
46  Incomplete,
47  PerformedWork,
48  HostEffectMask,
49  Snapshot,
50  Passive,
51  Deletion,
52  ContentReset,
53  Ref,
54  Placement,
55  Update,
56  Hydrating,
57  PlacementAndUpdate,
58  HydratingAndUpdate,
59} from './ReactFiberFlags';
60import { completeWork } from './ReactFiberCompleteWork';
61import { LegacyRoot } from './ReactRootTags';
62import {
63  HostRoot,
64  OffscreenComponent,
65  LegacyHiddenComponent,
66} from './ReactWorkTags';
67import { resetContextDependencies } from './ReactFiberNewContext';
68import {
69  noTimeout,
70  clearContainer,
71  prepareForCommit,
72  resetAfterCommit,
73} from './ReactFiberHostConfig';
74import ReactSharedInternals from '../../ReactSharedInternals';
75import {
76  commitBeforeMutationLifeCycles,
77  commitResetTextContent,
78  commitDetachRef,
79  commitPlacement,
80  commitWork,
81} from './ReactFiberCommitWork';
82
83const invariant = require('invariant');
84
85const { ReactCurrentDispatcher, ReactCurrentOwner } = ReactSharedInternals;
86
87const NoContext = 0b0000000;
88const BatchedContext = 0b0000001;
89const LegacyUnbatchedContext = 0b0001000;
90const RenderContext = 0b0010000;
91const CommitContext = 0b0100000;
92const DiscreteEventContext = 0b0000100;
93const RetryAfterError = 0b1000000;
94
95const RootIncomplete = 0;
96const RootErrored = 2;
97const RootSuspendedWithDelay = 4;
98const RootCompleted = 5;
99
100let executionContext = NoContext;
101let workInProgress = null;
102
103let workInProgressRootRenderTargetTime = Infinity;
104let workInProgressRootIncludedLanes = NoLanes;
105
106let currentEventTime = NoTimestamp;
107let currentEventWipLanes = NoLanes;
108
109const RENDER_TIMEOUT_MS = 500;
110
111const NESTED_UPDATE_LIMIT = 50;
112
113let nestedPassiveUpdateCount = 0;
114let nestedUpdateCount = 0;
115let rootWithNestedUpdates = null;
116
117let workInProgressRoot = null;
118let workInProgressRootUpdatedLanes = NoLanes;
119let workInProgressRootExitStatus = RootIncomplete;
120let workInProgressRootRenderLanes = NoLanes;
121let workInProgressRootPingedLanes = NoLanes;
122let workInProgressRootSkippedLanes = NoLanes;
123
124let subtreeRenderLanes = NoLanes;
125
126let workInProgressRootFatalError = null;
127let legacyErrorBoundariesThatAlreadyFailed = null;
128let hasUncaughtError = false;
129let firstUncaughtError = null;
130
131let nextEffect = null;
132
133let pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
134let rootWithPendingPassiveEffects = null;
135let pendingPassiveEffectsLanes = NoLanes;
136let rootDoesHavePassiveEffects = false;
137let pendingPassiveHookEffectsUnmount = [];
138
139let rootsWithPendingDiscreteUpdates = null;
140
141let mostRecentlyUpdatedRoot = null;
142
143const resetRenderTimer = () =>
144  (workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS);
145
146const unbatchedUpdates = (fn, a) => {
147  const prevExecutionContext = executionContext;
148  executionContext &= BatchedContext;
149  executionContext |= LegacyUnbatchedContext;
150
151  // executionContext: 8, prevExecutionContext: 0
152
153  try {
154    return fn(a);
155  } finally {
156    executionContext = prevExecutionContext;
157    if (executionContext === NoContext) {
158      resetRenderTimer();
159      flushSyncCallbackQueue();
160    }
161  }
162};
163
164const requestEventTime = () => {
165  if ((executionContext & (RenderContext | CommitContext)) !== NoContext)
166    return now();
167
168  if (currentEventTime !== NoTimestamp) return currentEventTime;
169
170  currentEventTime = now();
171
172  return currentEventTime;
173};
174
175const requestUpdateLane = (fiber) => {
176  const { mode } = fiber;
177  if ((mode & BlockingMode) === NoMode) return SyncLane;
178  else if ((mode & ConcurrentMode) === NoMode)
179    return getCurrentPriorityLevel() === ImmediateSchedulerPriority
180      ? SyncLane
181      : SyncBatchedLane;
182
183  if (currentEventWipLanes === NoLanes) {
184    currentEventWipLanes = workInProgressRootIncludedLanes;
185  }
186
187  const isTransition = requestCurrentTransition() !== NoTransition;
188
189  if (isTransition) {
190    // todo
191  }
192
193  const schedulerPriority = getCurrentPriorityLevel();
194  let lane;
195
196  if (
197    (executionContext & DiscreteEventContext) !== NoContext &&
198    schedulerPriority === UserBlockingPriority
199  )
200    lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
201  else {
202    const schedulerLanePriority =
203      schedulerPriorityToLanePriority(schedulerPriority);
204
205    lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
206  }
207
208  return lane;
209};
210
211const checkForNestedUpdates = () => {
212  if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
213    nestedUpdateCount = 0;
214    rootWithNestedUpdates = null;
215    invariant(
216      false,
217      'Maximum update depth exceeded. This can happen when a component ' +
218        'repeatedly calls setState inside componentWillUpdate or ' +
219        'componentDidUpdate. React limits the number of nested updates to ' +
220        'prevent infinite loops.'
221    );
222  }
223};
224
225const markUpdateLaneFromFiberToRoot = (sourceFiber, lane) => {
226  sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);
227  let { alternate } = sourceFiber;
228  if (alternate !== null) {
229    alternate.lanes = mergeLanes(alternate.lanes, lane);
230  }
231
232  let node = sourceFiber;
233  let parent = sourceFiber.return;
234  while (parent !== null) {
235    parent.childLanes = mergeLanes(parent.childLanes, lane);
236    alternate = parent.alternate;
237    if (alternate !== null) {
238      alternate.childLanes = mergeLanes(alternate.childLanes, lane);
239    }
240    node = parent;
241    parent = parent.return;
242  }
243
244  if (node.tag === HostRoot) {
245    const root = node.stateNode;
246    return root;
247  } else {
248    return null;
249  }
250};
251
252const markRootSuspended = (root, suspendedLanes) => {
253  suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);
254  suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);
255
256  markRootSuspendedDontCallThisOneDirectly(root, suspendedLanes);
257};
258
259const detachFiberAfterEffects = (fiber) => {
260  fiber.sibling = null;
261  fiber.stateNode = null;
262};
263
264const flushPassiveEffectsImpl = () => {
265  if (rootWithPendingPassiveEffects === null) return false;
266
267  const root = rootWithPendingPassiveEffects;
268  rootWithPendingPassiveEffects = null;
269  pendingPassiveEffectsLanes = NoLanes;
270
271  invariant(
272    (executionContext & (RenderContext | CommitContext)) === NoContext,
273    'Cannot flush passive effects while already rendering.'
274  );
275
276  const prevExecutionContext = executionContext;
277  executionContext |= CommitContext;
278
279  pendingPassiveHookEffectsUnmount = [];
280
281  pendingPassiveHookEffectsMount = [];
282
283  let effect = root.current.firstEffect;
284  while (effect !== null) {
285    const nextNextEffect = effect.nextEffect;
286    effect.nextEffect = null;
287    if (effect.flags & Deletion) {
288      detachFiberAfterEffects(effect);
289    }
290    effect = nextNextEffect;
291  }
292
293  executionContext = prevExecutionContext;
294
295  flushSyncCallbackQueue();
296
297  nestedPassiveUpdateCount =
298    rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;
299
300  return true;
301};
302
303const flushPassiveEffects = () => {
304  if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
305    const priorityLevel =
306      pendingPassiveEffectsRenderPriority > NormalSchedulerPriority
307        ? NormalSchedulerPriority
308        : pendingPassiveEffectsRenderPriority;
309    pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
310
311    return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
312  }
313  return false;
314};
315
316const pushDispatcher = () => {
317  const prevDispatcher = ReactCurrentDispatcher.current;
318  ReactCurrentDispatcher.current = ContextOnlyDispatcher;
319  if (prevDispatcher === null) {
320    return ContextOnlyDispatcher;
321  } else {
322    return prevDispatcher;
323  }
324};
325
326const popDispatcher = (prevDispatcher) => {
327  ReactCurrentDispatcher.current = prevDispatcher;
328};
329
330const prepareFreshStack = (root, lanes) => {
331  root.finishedWork = null;
332  root.finishedLanes = NoLanes;
333
334  const timeoutHandle = root.timeoutHandle;
335  if (timeoutHandle !== noTimeout) {
336    root.timeoutHandle = noTimeout;
337    clearTimeout(timeoutHandle);
338  }
339
340  if (workInProgress !== null) {
341    let interruptedWork = workInProgress.return;
342    while (interruptedWork !== null) {
343      unwindInterruptedWork(interruptedWork);
344      interruptedWork = interruptedWork.return;
345    }
346  }
347
348  workInProgressRoot = root;
349  workInProgress = createWorkInProgress(root.current, null);
350
351  workInProgressRootRenderLanes =
352    subtreeRenderLanes =
353    workInProgressRootIncludedLanes =
354      lanes;
355  workInProgressRootExitStatus = RootIncomplete;
356  workInProgressRootFatalError = null;
357  workInProgressRootSkippedLanes = NoLanes;
358  workInProgressRootUpdatedLanes = NoLanes;
359  workInProgressRootPingedLanes = NoLanes;
360};
361
362const resetChildLanes = (completedWork) => {
363  if (
364    (completedWork.tag === LegacyHiddenComponent ||
365      completedWork.tag === OffscreenComponent) &&
366    completedWork.memoizedState !== null &&
367    !includesSomeLane(subtreeRenderLanes, OffscreenLane) &&
368    (completedWork.mode & ConcurrentMode) !== NoLanes
369  )
370    return;
371
372  let newChildLanes = NoLanes;
373
374  let child = completedWork.child;
375  while (child !== null) {
376    newChildLanes = mergeLanes(
377      newChildLanes,
378      mergeLanes(child.lanes, child.childLanes)
379    );
380    child = child.sibling;
381  }
382
383  completedWork.childLanes = newChildLanes;
384};
385
386const completeUnitOfWork = (unitOfWork) => {
387  let completedWork = unitOfWork;
388  do {
389    const current = completedWork.alternate;
390    const returnFiber = completedWork.return;
391
392    console.log(completedWork, '------completeUnitOfWork:completedWork');
393
394    if ((completedWork.flags & Incomplete) === NoFlags) {
395      const next = completeWork(current, completedWork, subtreeRenderLanes);
396      console.log(next, '------completeUnitOfWork:next');
397
398      if (next !== null) {
399        workInProgress = next;
400        return;
401      }
402
403      resetChildLanes(completedWork);
404
405      if (
406        returnFiber !== null &&
407        (returnFiber.flags & Incomplete) === NoFlags
408      ) {
409        if (returnFiber.firstEffect === null) {
410          returnFiber.firstEffect = completedWork.firstEffect;
411        }
412        if (completedWork.lastEffect !== null) {
413          if (returnFiber.lastEffect !== null) {
414            returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
415          }
416          returnFiber.lastEffect = completedWork.lastEffect;
417        }
418
419        const flags = completedWork.flags;
420
421        if (flags > PerformedWork) {
422          if (returnFiber.lastEffect !== null) {
423            returnFiber.lastEffect.nextEffect = completedWork;
424          } else {
425            returnFiber.firstEffect = completedWork;
426          }
427          returnFiber.lastEffect = completedWork;
428        }
429      }
430    } else {
431      const next = unwindWork(completedWork, subtreeRenderLanes);
432
433      if (next !== null) {
434        next.flags &= HostEffectMask;
435        workInProgress = next;
436        return;
437      }
438
439      if (returnFiber !== null) {
440        returnFiber.firstEffect = returnFiber.lastEffect = null;
441        returnFiber.flags |= Incomplete;
442      }
443    }
444
445    const siblingFiber = completedWork.sibling;
446    if (siblingFiber !== null) {
447      workInProgress = siblingFiber;
448      return;
449    }
450
451    completedWork = returnFiber;
452    workInProgress = completedWork;
453  } while (completedWork !== null);
454
455  if (workInProgressRootExitStatus === RootIncomplete) {
456    workInProgressRootExitStatus = RootCompleted;
457  }
458};
459
460const performUnitOfWork = (unitOfWork) => {
461  const current = unitOfWork.alternate;
462
463  console.log({ ...unitOfWork }, '--------performUnitOfWork(workInProgress)');
464  const next = beginWork(current, unitOfWork, subtreeRenderLanes);
465  console.log({ ...next }, '--------performUnitOfWork:next');
466
467  unitOfWork.memoizedProps = unitOfWork.pendingProps;
468
469  if (next === null) {
470    completeUnitOfWork(unitOfWork);
471  } else {
472    workInProgress = next;
473  }
474
475  ReactCurrentOwner.current = null;
476};
477
478const workLoopSync = () => {
479  while (workInProgress !== null) {
480    performUnitOfWork(workInProgress);
481  }
482};
483
484const commitBeforeMutationEffects = () => {
485  while (nextEffect !== null) {
486    const current = nextEffect.alternate;
487
488    const flags = nextEffect.flags;
489    if ((flags & Snapshot) !== NoFlags) {
490      commitBeforeMutationLifeCycles(current, nextEffect);
491    }
492    if ((flags & Passive) !== NoFlags) {
493      if (!rootDoesHavePassiveEffects) {
494        rootDoesHavePassiveEffects = true;
495        scheduleCallback(NormalSchedulerPriority, () => {
496          flushPassiveEffects();
497          return null;
498        });
499      }
500    }
501
502    nextEffect = nextEffect.nextEffect;
503  }
504};
505
506const commitMutationEffects = (root, renderPriorityLevel) => {
507  while (nextEffect !== null) {
508    const flags = nextEffect.flags;
509
510    if (flags & ContentReset) {
511      commitResetTextContent(nextEffect);
512    }
513
514    if (flags & Ref) {
515      const current = nextEffect.alternate;
516      if (current !== null) {
517        commitDetachRef(current);
518      }
519    }
520
521    const primaryFlags = flags & (Placement | Update | Deletion | Hydrating);
522    console.log(primaryFlags, '------commitMutationEffects:primaryFlags');
523    switch (primaryFlags) {
524      case Placement: {
525        commitPlacement(nextEffect);
526
527        nextEffect.flags &= ~Placement;
528        break;
529      }
530      case PlacementAndUpdate: {
531        commitPlacement(nextEffect);
532
533        nextEffect.flags &= ~Placement;
534
535        const current = nextEffect.alternate;
536        commitWork(current, nextEffect);
537        break;
538      }
539      case Hydrating: {
540        nextEffect.flags &= ~Hydrating;
541        break;
542      }
543      case HydratingAndUpdate: {
544        nextEffect.flags &= ~Hydrating;
545
546        const current = nextEffect.alternate;
547        commitWork(current, nextEffect);
548        break;
549      }
550      case Update: {
551        const current = nextEffect.alternate;
552        commitWork(current, nextEffect);
553        break;
554      }
555      case Deletion: {
556        commitDeletion(root, nextEffect, renderPriorityLevel);
557        break;
558      }
559    }
560
561    nextEffect = nextEffect.nextEffect;
562  }
563};
564
565const commitLayoutEffects = (root, committedLanes) => {};
566
567const commitRootImpl = (root, renderPriorityLevel) => {
568  do {
569    flushPassiveEffects();
570  } while (rootWithPendingPassiveEffects !== null);
571
572  console.log(executionContext, '------commitRootImpl:executionContext');
573
574  invariant(
575    (executionContext & (RenderContext | CommitContext)) === NoContext,
576    'Should not already be working.'
577  );
578
579  const finishedWork = root.finishedWork;
580  const lanes = root.finishedLanes;
581
582  if (finishedWork === null) return null;
583
584  root.finishedWork = null;
585  root.finishedLanes = NoLanes;
586
587  invariant(
588    finishedWork !== root.current,
589    'Cannot commit the same tree as before. This error is likely caused by ' +
590      'a bug in React. Please file an issue.'
591  );
592
593  root.callbackNode = null;
594
595  let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
596  markRootFinished(root, remainingLanes);
597
598  if (rootsWithPendingDiscreteUpdates !== null) {
599    if (
600      !hasDiscreteLanes(remainingLanes) &&
601      rootsWithPendingDiscreteUpdates.has(root)
602    ) {
603      rootsWithPendingDiscreteUpdates.delete(root);
604    }
605  }
606
607  if (root === workInProgressRoot) {
608    workInProgressRoot = null;
609    workInProgress = null;
610    workInProgressRootRenderLanes = NoLanes;
611  }
612
613  let firstEffect;
614  if (finishedWork.flags > PerformedWork) {
615    if (finishedWork.lastEffect !== null) {
616      finishedWork.lastEffect.nextEffect = finishedWork;
617      firstEffect = finishedWork.firstEffect;
618    } else {
619      firstEffect = finishedWork;
620    }
621  } else {
622    firstEffect = finishedWork.firstEffect;
623  }
624
625  if (firstEffect !== null) {
626    const prevExecutionContext = executionContext;
627    executionContext |= CommitContext;
628
629    ReactCurrentOwner.current = null;
630
631    prepareForCommit(root.containerInfo);
632
633    nextEffect = firstEffect;
634
635    do {
636      try {
637        commitBeforeMutationEffects();
638      } catch (error) {
639        invariant(nextEffect !== null, 'Should be working on an effect.');
640        // captureCommitPhaseError(nextEffect, error);
641        nextEffect = nextEffect.nextEffect;
642      }
643    } while (nextEffect !== null);
644
645    nextEffect = firstEffect;
646
647    console.log({ ...nextEffect }, '------commitMutationEffects>nextEffect');
648
649    do {
650      try {
651        commitMutationEffects(root, renderPriorityLevel);
652      } catch (error) {
653        invariant(nextEffect !== null, 'Should be working on an effect.');
654        // captureCommitPhaseError(nextEffect, error);
655        nextEffect = nextEffect.nextEffect;
656      }
657    } while (nextEffect !== null);
658
659    resetAfterCommit(root.containerInfo);
660
661    root.current = finishedWork;
662    nextEffect = firstEffect;
663
664    // do {
665    //   try {
666    //     commitLayoutEffects(root, lanes);
667    //   } catch (error) {
668    //     invariant(nextEffect !== null, 'Should be working on an effect.');
669
670    //     nextEffect = nextEffect.nextEffect;
671    //   }
672    // } while (nextEffect !== null);
673
674    nextEffect = null;
675
676    requestPaint();
677
678    executionContext = prevExecutionContext;
679  } else {
680    root.current = finishedWork;
681  }
682
683  const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;
684
685  if (rootDoesHavePassiveEffects) {
686    rootDoesHavePassiveEffects = false;
687    rootWithPendingPassiveEffects = root;
688    pendingPassiveEffectsLanes = lanes;
689    pendingPassiveEffectsRenderPriority = renderPriorityLevel;
690  } else {
691    nextEffect = firstEffect;
692    while (nextEffect !== null) {
693      const nextNextEffect = nextEffect.nextEffect;
694      nextEffect.nextEffect = null;
695      if (nextEffect.flags & Deletion) {
696        detachFiberAfterEffects(nextEffect);
697      }
698      nextEffect = nextNextEffect;
699    }
700  }
701
702  remainingLanes = root.pendingLanes;
703
704  legacyErrorBoundariesThatAlreadyFailed = null;
705
706  if (remainingLanes === SyncLane) {
707    if (root === rootWithNestedUpdates) {
708      nestedUpdateCount++;
709    } else {
710      nestedUpdateCount = 0;
711      rootWithNestedUpdates = root;
712    }
713  } else {
714    nestedUpdateCount = 0;
715  }
716
717  ensureRootIsScheduled(root, now());
718
719  if (hasUncaughtError) {
720    hasUncaughtError = false;
721    const error = firstUncaughtError;
722    firstUncaughtError = null;
723    throw error;
724  }
725
726  if ((executionContext & LegacyUnbatchedContext) !== NoContext) return null;
727
728  flushSyncCallbackQueue();
729
730  return null;
731};
732
733const commitRoot = (root) => {
734  const renderPriorityLevel = getCurrentPriorityLevel();
735  console.log(renderPriorityLevel, '------commitRoot:renderPriorityLevel');
736  runWithPriority(
737    ImmediateSchedulerPriority,
738    commitRootImpl.bind(null, root, renderPriorityLevel)
739  );
740  return null;
741};
742
743const renderRootSync = (root, lanes) => {
744  const prevExecutionContext = executionContext;
745  executionContext |= RenderContext;
746  const prevDispatcher = pushDispatcher();
747
748  if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
749    prepareFreshStack(root, lanes);
750  }
751
752  do {
753    try {
754      workLoopSync();
755      break;
756    } catch (thrownValue) {
757      // handleError(root, thrownValue);
758    }
759  } while (true);
760
761  resetContextDependencies();
762  executionContext = prevExecutionContext;
763
764  popDispatcher(prevDispatcher);
765
766  if (workInProgress !== null) {
767    invariant(
768      false,
769      'Cannot commit an incomplete root. This error is likely caused by a ' +
770        'bug in React. Please file an issue.'
771    );
772  }
773
774  workInProgressRoot = null;
775  workInProgressRootRenderLanes = NoLanes;
776
777  return workInProgressRootExitStatus;
778};
779
780const ensureRootIsScheduled = (root, currentTime) => {
781  const existingCallbackNode = root.callbackNode;
782
783  markStarvedLanesAsExpired(root, currentTime);
784
785  const nextLanes = getNextLanes(
786    root,
787    root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes
788  );
789  const newCallbackPriority = returnNextLanesPriority();
790
791  if (nextLanes === NoLanes) {
792    if (existingCallbackNode !== null) {
793      cancelCallback(existingCallbackNode);
794      root.callbackNode = null;
795      root.callbackPriority = NoLanePriority;
796    }
797    return;
798  }
799
800  if (existingCallbackNode !== null) {
801    const existingCallbackPriority = root.callbackPriority;
802    if (existingCallbackPriority === newCallbackPriority) return;
803
804    cancelCallback(existingCallbackNode);
805  }
806
807  let newCallbackNode;
808  if (newCallbackPriority === SyncLanePriority) {
809    newCallbackNode = scheduleSyncCallback(
810      performSyncWorkOnRoot.bind(null, root)
811    );
812  } else if (newCallbackPriority === SyncBatchedLanePriority) {
813    newCallbackNode = scheduleCallback(
814      ImmediateSchedulerPriority,
815      performSyncWorkOnRoot.bind(null, root)
816    );
817  } else {
818    const schedulerPriorityLevel =
819      lanePriorityToSchedulerPriority(newCallbackPriority);
820    newCallbackNode = scheduleCallback(
821      schedulerPriorityLevel,
822      performConcurrentWorkOnRoot.bind(null, root)
823    );
824  }
825
826  root.callbackPriority = newCallbackPriority;
827  root.callbackNode = newCallbackNode;
828};
829
830const performSyncWorkOnRoot = (root) => {
831  invariant(
832    (executionContext & (RenderContext | CommitContext)) === NoContext,
833    'Should not already be working.'
834  );
835
836  flushPassiveEffects();
837
838  let lanes;
839  let exitStatus;
840  if (
841    root === workInProgressRoot &&
842    includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)
843  ) {
844    lanes = workInProgressRootRenderLanes;
845    exitStatus = renderRootSync(root, lanes);
846    if (
847      includesSomeLane(
848        workInProgressRootIncludedLanes,
849        workInProgressRootUpdatedLanes
850      )
851    ) {
852      lanes = getNextLanes(root, lanes);
853      exitStatus = renderRootSync(root, lanes);
854    }
855  } else {
856    lanes = getNextLanes(root, NoLanes);
857    exitStatus = renderRootSync(root, lanes);
858  }
859
860  if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
861    executionContext |= RetryAfterError;
862
863    if (root.hydrate) {
864      root.hydrate = false;
865      clearContainer(root.containerInfo);
866    }
867  }
868
869  const finishedWork = root.current.alternate;
870  root.finishedWork = finishedWork;
871  root.finishedLanes = lanes;
872
873  console.log({ ...root }, '------performSyncWorkOnRoot>commitRoot(root)');
874  commitRoot(root);
875
876  ensureRootIsScheduled(root, now());
877
878  return null;
879};
880
881const scheduleUpdateOnFiber = (fiber, lane, eventTime) => {
882  checkForNestedUpdates();
883
884  const root = markUpdateLaneFromFiberToRoot(fiber, lane);
885
886  if (root === null) return null;
887
888  markRootUpdated(root, lane, eventTime);
889
890  if (root === workInProgressRoot) {
891    if ((executionContext & RenderContext) === NoContext) {
892      workInProgressRootUpdatedLanes = mergeLanes(
893        workInProgressRootUpdatedLanes,
894        lane
895      );
896    }
897    if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
898      markRootSuspended(root, workInProgressRootRenderLanes);
899    }
900  }
901
902  if (lane === SyncLane) {
903    if (
904      (executionContext & LegacyUnbatchedContext) !== NoContext &&
905      (executionContext & (RenderContext | CommitContext)) === NoContext
906    ) {
907      performSyncWorkOnRoot(root);
908    } else {
909      ensureRootIsScheduled(root, eventTime);
910      if (executionContext === NoContext) {
911        resetRenderTimer();
912        flushSyncCallbackQueue();
913      }
914    }
915  } else {
916    if (
917      (executionContext & DiscreteEventContext) !== NoContext &&
918      (priorityLevel === UserBlockingSchedulerPriority ||
919        priorityLevel === ImmediateSchedulerPriority)
920    ) {
921      if (rootsWithPendingDiscreteUpdates === null) {
922        rootsWithPendingDiscreteUpdates = new Set([root]);
923      } else {
924        rootsWithPendingDiscreteUpdates.add(root);
925      }
926    }
927    ensureRootIsScheduled(root, eventTime);
928  }
929
930  mostRecentlyUpdatedRoot = root;
931};
932
933const markSkippedUpdateLanes = (lane) => {
934  workInProgressRootSkippedLanes = mergeLanes(
935    lane,
936    workInProgressRootSkippedLanes
937  );
938};
939
940const performConcurrentWorkOnRoot = (root) => {};
941
942export {
943  NoContext,
944  RetryAfterError,
945  unbatchedUpdates,
946  requestEventTime,
947  requestUpdateLane,
948  flushPassiveEffects,
949  scheduleUpdateOnFiber,
950  markSkippedUpdateLanes,
951};
952
Full Screen

ReactFiberWorkLoop.old.js

Source: ReactFiberWorkLoop.old.js Github

copy
1  var ceil = Math.ceil;
2  var ReactCurrentDispatcher$2 = ReactSharedInternals.ReactCurrentDispatcher,
3      ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner,
4      IsSomeRendererActing = ReactSharedInternals.IsSomeRendererActing;
5  var NoContext =
6  /*             */
7  0;
8  var BatchedContext =
9  /*               */
10  1;
11  var EventContext =
12  /*                 */
13  2;
14  var DiscreteEventContext =
15  /*         */
16  4;
17  var LegacyUnbatchedContext =
18  /*       */
19  8;
20  var RenderContext =
21  /*                */
22  16;
23  var CommitContext =
24  /*                */
25  32;
26  var RetryAfterError =
27  /*       */
28  64;
29  var RootIncomplete = 0;
30  var RootFatalErrored = 1;
31  var RootErrored = 2;
32  var RootSuspended = 3;
33  var RootSuspendedWithDelay = 4;
34  var RootCompleted = 5; // Describes where we are in the React execution stack
35
36  var executionContext = NoContext; // The root we're working on
37
38  var workInProgressRoot = null; // The fiber we're working on
39
40  var workInProgress = null; // The lanes we're rendering
41
42  var workInProgressRootRenderLanes = NoLanes; // Stack that allows components to change the render lanes for its subtree
43  // This is a superset of the lanes we started working on at the root. The only
44  // case where it's different from `workInProgressRootRenderLanes` is when we
45  // enter a subtree that is hidden and needs to be unhidden: Suspense and
46  // Offscreen component.
47  //
48  // Most things in the work loop should deal with workInProgressRootRenderLanes.
49  // Most things in begin/complete phases should deal with subtreeRenderLanes.
50
51  var subtreeRenderLanes = NoLanes;
52  var subtreeRenderLanesCursor = createCursor(NoLanes); // Whether to root completed, errored, suspended, etc.
53
54  var workInProgressRootExitStatus = RootIncomplete; // A fatal error, if one is thrown
55
56  var workInProgressRootFatalError = null; // "Included" lanes refer to lanes that were worked on during this render. It's
57  // slightly different than `renderLanes` because `renderLanes` can change as you
58  // enter and exit an Offscreen tree. This value is the combination of all render
59  // lanes for the entire render phase.
60
61  var workInProgressRootIncludedLanes = NoLanes; // The work left over by components that were visited during this render. Only
62  // includes unprocessed updates, not work in bailed out children.
63
64  var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render.
65
66  var workInProgressRootUpdatedLanes = NoLanes; // Lanes that were pinged (in an interleaved event) during this render.
67
68  var workInProgressRootPingedLanes = NoLanes;
69  var mostRecentlyUpdatedRoot = null; // The most recent time we committed a fallback. This lets us ensure a train
70  // model where we don't commit new loading states in too quick succession.
71
72  var globalMostRecentFallbackTime = 0;
73  var FALLBACK_THROTTLE_MS = 500; // The absolute time for when we should start giving up on rendering
74  // more and prefer CPU suspense heuristics instead.
75
76  var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU
77  // suspense heuristics and opt out of rendering more content.
78
79  var RENDER_TIMEOUT_MS = 500;
80
81  function resetRenderTimer() {
82    workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;
83  }
84
85  function getRenderTargetTime() {
86    return workInProgressRootRenderTargetTime;
87  }
88  var nextEffect = null;
89  var hasUncaughtError = false;
90  var firstUncaughtError = null;
91  var legacyErrorBoundariesThatAlreadyFailed = null;
92  var rootDoesHavePassiveEffects = false;
93  var rootWithPendingPassiveEffects = null;
94  var pendingPassiveEffectsRenderPriority = NoPriority$1;
95  var pendingPassiveEffectsLanes = NoLanes;
96  var pendingPassiveHookEffectsMount = [];
97  var pendingPassiveHookEffectsUnmount = [];
98  var rootsWithPendingDiscreteUpdates = null; // Use these to prevent an infinite loop of nested updates
99
100  var NESTED_UPDATE_LIMIT = 50;
101  var nestedUpdateCount = 0;
102  var rootWithNestedUpdates = null;
103  var NESTED_PASSIVE_UPDATE_LIMIT = 50;
104  var nestedPassiveUpdateCount = 0; // Marks the need to reschedule pending interactions at these lanes
105  // during the commit phase. This enables them to be traced across components
106  // that spawn new work during render. E.g. hidden boundaries, suspended SSR
107  // hydration or SuspenseList.
108  // TODO: Can use a bitmask instead of an array
109
110  var spawnedWorkDuringRender = null; // If two updates are scheduled within the same event, we should treat their
111  // event times as simultaneous, even if the actual clock time has advanced
112  // between the first and second call.
113
114  var currentEventTime = NoTimestamp;
115  var currentEventWipLanes = NoLanes;
116  var currentEventPendingLanes = NoLanes; // Dev only flag that tracks if passive effects are currently being flushed.
117  // We warn about state updates for unmounted components differently in this case.
118
119  var isFlushingPassiveEffects = false;
120  var focusedInstanceHandle = null;
121  var shouldFireAfterActiveInstanceBlur = false;
122  function getWorkInProgressRoot() {
123    return workInProgressRoot;
124  }
125  function requestEventTime() {
126    if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
127      // We're inside React, so it's fine to read the actual time.
128      return now();
129    } // We're not inside React, so we may be in the middle of a browser event.
130
131
132    if (currentEventTime !== NoTimestamp) {
133      // Use the same start time for all updates until we enter React again.
134      return currentEventTime;
135    } // This is the first update since React yielded. Compute a new start time.
136
137
138    currentEventTime = now();
139    return currentEventTime;
140  }
141  function requestUpdateLane(fiber) {
142    // Special cases
143    var mode = fiber.mode;
144
145    if ((mode & BlockingMode) === NoMode) {
146      return SyncLane;
147    } else if ((mode & ConcurrentMode) === NoMode) {
148      return getCurrentPriorityLevel() === ImmediatePriority$1 ? SyncLane : SyncBatchedLane;
149    } // The algorithm for assigning an update to a lane should be stable for all
150    // updates at the same priority within the same event. To do this, the inputs
151    // to the algorithm must be the same. For example, we use the `renderLanes`
152    // to avoid choosing a lane that is already in the middle of rendering.
153    //
154    // However, the "included" lanes could be mutated in between updates in the
155    // same event, like if you perform an update inside `flushSync`. Or any other
156    // code path that might call `prepareFreshStack`.
157    //
158    // The trick we use is to cache the first of each of these inputs within an
159    // event. Then reset the cached values once we can be sure the event is over.
160    // Our heuristic for that is whenever we enter a concurrent work loop.
161    //
162    // We'll do the same for `currentEventPendingLanes` below.
163
164
165    if (currentEventWipLanes === NoLanes) {
166      currentEventWipLanes = workInProgressRootIncludedLanes;
167    }
168
169    var isTransition = requestCurrentTransition() !== NoTransition;
170
171    if (isTransition) {
172      if (currentEventPendingLanes !== NoLanes) {
173        currentEventPendingLanes = mostRecentlyUpdatedRoot !== null ? mostRecentlyUpdatedRoot.pendingLanes : NoLanes;
174      }
175
176      return findTransitionLane(currentEventWipLanes, currentEventPendingLanes);
177    } // TODO: Remove this dependency on the Scheduler priority.
178    // To do that, we're replacing it with an update lane priority.
179
180
181    var schedulerPriority = getCurrentPriorityLevel(); // The old behavior was using the priority level of the Scheduler.
182    // This couples React to the Scheduler internals, so we're replacing it
183    // with the currentUpdateLanePriority above. As an example of how this
184    // could be problematic, if we're not inside `Scheduler.runWithPriority`,
185    // then we'll get the priority of the current running Scheduler task,
186    // which is probably not what we want.
187
188    var lane;
189
190    if ( // TODO: Temporary. We're removing the concept of discrete updates.
191    (executionContext & DiscreteEventContext) !== NoContext && schedulerPriority === UserBlockingPriority$2) {
192      lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
193    } else {
194      var schedulerLanePriority = schedulerPriorityToLanePriority(schedulerPriority);
195
196      lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
197    }
198
199    return lane;
200  }
201
202  function requestRetryLane(fiber) {
203    // This is a fork of `requestUpdateLane` designed specifically for Suspense
204    // "retries" — a special update that attempts to flip a Suspense boundary
205    // from its placeholder state to its primary/resolved state.
206    // Special cases
207    var mode = fiber.mode;
208
209    if ((mode & BlockingMode) === NoMode) {
210      return SyncLane;
211    } else if ((mode & ConcurrentMode) === NoMode) {
212      return getCurrentPriorityLevel() === ImmediatePriority$1 ? SyncLane : SyncBatchedLane;
213    } // See `requestUpdateLane` for explanation of `currentEventWipLanes`
214
215
216    if (currentEventWipLanes === NoLanes) {
217      currentEventWipLanes = workInProgressRootIncludedLanes;
218    }
219
220    return findRetryLane(currentEventWipLanes);
221  }
222
223  function scheduleUpdateOnFiber(fiber, lane, eventTime) {
224    checkForNestedUpdates();
225    warnAboutRenderPhaseUpdatesInDEV(fiber);
226    var root = markUpdateLaneFromFiberToRoot(fiber, lane);
227
228    if (root === null) {
229      warnAboutUpdateOnUnmountedFiberInDEV(fiber);
230      return null;
231    } // Mark that the root has a pending update.
232
233
234    markRootUpdated(root, lane, eventTime);
235
236    if (root === workInProgressRoot) {
237      // Received an update to a tree that's in the middle of rendering. Mark
238      // that there was an interleaved update work on this root. Unless the
239      // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render
240      // phase update. In that case, we don't treat render phase updates as if
241      // they were interleaved, for backwards compat reasons.
242      {
243        workInProgressRootUpdatedLanes = mergeLanes(workInProgressRootUpdatedLanes, lane);
244      }
245
246      if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
247        // The root already suspended with a delay, which means this render
248        // definitely won't finish. Since we have a new update, let's mark it as
249        // suspended now, right before marking the incoming update. This has the
250        // effect of interrupting the current render and switching to the update.
251        // TODO: Make sure this doesn't override pings that happen while we've
252        // already started rendering.
253        markRootSuspended$1(root, workInProgressRootRenderLanes);
254      }
255    } // TODO: requestUpdateLanePriority also reads the priority. Pass the
256    // priority as an argument to that function and this one.
257
258
259    var priorityLevel = getCurrentPriorityLevel();
260
261    if (lane === SyncLane) {
262      if ( // Check if we're inside unbatchedUpdates
263      (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering
264      (executionContext & (RenderContext | CommitContext)) === NoContext) {
265        // Register pending interactions on the root to avoid losing traced interaction data.
266        schedulePendingInteractions(root, lane); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed
267        // root inside of batchedUpdates should be synchronous, but layout updates
268        // should be deferred until the end of the batch.
269
270        performSyncWorkOnRoot(root);
271      } else {
272        ensureRootIsScheduled(root, eventTime);
273        schedulePendingInteractions(root, lane);
274
275        if (executionContext === NoContext) {
276          // Flush the synchronous work now, unless we're already working or inside
277          // a batch. This is intentionally inside scheduleUpdateOnFiber instead of
278          // scheduleCallbackForFiber to preserve the ability to schedule a callback
279          // without immediately flushing it. We only do this for user-initiated
280          // updates, to preserve historical behavior of legacy mode.
281          resetRenderTimer();
282          flushSyncCallbackQueue();
283        }
284      }
285    } else {
286      // Schedule a discrete update but only if it's not Sync.
287      if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered
288      // discrete, even inside a discrete event.
289      priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority$1)) {
290        // This is the result of a discrete event. Track the lowest priority
291        // discrete update per root so we can flush them early, if needed.
292        if (rootsWithPendingDiscreteUpdates === null) {
293          rootsWithPendingDiscreteUpdates = new Set([root]);
294        } else {
295          rootsWithPendingDiscreteUpdates.add(root);
296        }
297      } // Schedule other updates after in case the callback is sync.
298
299
300      ensureRootIsScheduled(root, eventTime);
301      schedulePendingInteractions(root, lane);
302    } // We use this when assigning a lane for a transition inside
303    // `requestUpdateLane`. We assume it's the same as the root being updated,
304    // since in the common case of a single root app it probably is. If it's not
305    // the same root, then it's not a huge deal, we just might batch more stuff
306    // together more than necessary.
307
308
309    mostRecentlyUpdatedRoot = root;
310  } // This is split into a separate function so we can mark a fiber with pending
311  // work without treating it as a typical update that originates from an event;
312  // e.g. retrying a Suspense boundary isn't an update, but it does schedule work
313  // on a fiber.
314
315  function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {
316    // Update the source fiber's lanes
317    sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);
318    var alternate = sourceFiber.alternate;
319
320    if (alternate !== null) {
321      alternate.lanes = mergeLanes(alternate.lanes, lane);
322    }
323
324    {
325      if (alternate === null && (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags) {
326        warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);
327      }
328    } // Walk the parent path to the root and update the child expiration time.
329
330
331    var node = sourceFiber;
332    var parent = sourceFiber.return;
333
334    while (parent !== null) {
335      parent.childLanes = mergeLanes(parent.childLanes, lane);
336      alternate = parent.alternate;
337
338      if (alternate !== null) {
339        alternate.childLanes = mergeLanes(alternate.childLanes, lane);
340      } else {
341        {
342          if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {
343            warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);
344          }
345        }
346      }
347
348      node = parent;
349      parent = parent.return;
350    }
351
352    if (node.tag === HostRoot) {
353      var root = node.stateNode;
354      return root;
355    } else {
356      return null;
357    }
358  } // Use this function to schedule a task for a root. There's only one task per
359  // root; if a task was already scheduled, we'll check to make sure the priority
360  // of the existing task is the same as the priority of the next level that the
361  // root has work on. This function is called on every update, and right before
362  // exiting a task.
363
364
365  function ensureRootIsScheduled(root, currentTime) {
366    var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as
367    // expired so we know to work on those next.
368
369    markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority.
370
371    var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); // This returns the priority level computed during the `getNextLanes` call.
372
373    var newCallbackPriority = returnNextLanesPriority();
374
375    if (nextLanes === NoLanes) {
376      // Special case: There's nothing to work on.
377      if (existingCallbackNode !== null) {
378        cancelCallback(existingCallbackNode);
379        root.callbackNode = null;
380        root.callbackPriority = NoLanePriority;
381      }
382
383      return;
384    } // Check if there's an existing task. We may be able to reuse it.
385
386
387    if (existingCallbackNode !== null) {
388      var existingCallbackPriority = root.callbackPriority;
389
390      if (existingCallbackPriority === newCallbackPriority) {
391        // The priority hasn't changed. We can reuse the existing task. Exit.
392        return;
393      } // The priority changed. Cancel the existing callback. We'll schedule a new
394      // one below.
395
396
397      cancelCallback(existingCallbackNode);
398    } // Schedule a new callback.
399
400
401    var newCallbackNode;
402
403    if (newCallbackPriority === SyncLanePriority) {
404      // Special case: Sync React callbacks are scheduled on a special
405      // internal queue
406      newCallbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
407    } else if (newCallbackPriority === SyncBatchedLanePriority) {
408      newCallbackNode = scheduleCallback(ImmediatePriority$1, performSyncWorkOnRoot.bind(null, root));
409    } else {
410      var schedulerPriorityLevel = lanePriorityToSchedulerPriority(newCallbackPriority);
411      newCallbackNode = scheduleCallback(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));
412    }
413
414    root.callbackPriority = newCallbackPriority;
415    root.callbackNode = newCallbackNode;
416  } // This is the entry point for every concurrent task, i.e. anything that
417  // goes through Scheduler.
418
419
420  function performConcurrentWorkOnRoot(root) {
421    // Since we know we're in a React event, we can clear the current
422    // event time. The next update will compute a new event time.
423    currentEventTime = NoTimestamp;
424    currentEventWipLanes = NoLanes;
425    currentEventPendingLanes = NoLanes;
426
427    if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {
428      {
429        throw Error( "Should not already be working." );
430      }
431    } // Flush any pending passive effects before deciding which lanes to work on,
432    // in case they schedule additional work.
433
434
435    var originalCallbackNode = root.callbackNode;
436    var didFlushPassiveEffects = flushPassiveEffects();
437
438    if (didFlushPassiveEffects) {
439      // Something in the passive effect phase may have canceled the current task.
440      // Check if the task node for this root was changed.
441      if (root.callbackNode !== originalCallbackNode) {
442        // The current task was canceled. Exit. We don't need to call
443        // `ensureRootIsScheduled` because the check above implies either that
444        // there's a new task, or that there's no remaining work on this root.
445        return null;
446      }
447    } // Determine the next expiration time to work on, using the fields stored
448    // on the root.
449
450
451    var lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);
452
453    if (lanes === NoLanes) {
454      // Defensive coding. This is never expected to happen.
455      return null;
456    }
457
458    var exitStatus = renderRootConcurrent(root, lanes);
459
460    if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {
461      // The render included lanes that were updated during the render phase.
462      // For example, when unhiding a hidden tree, we include all the lanes
463      // that were previously skipped when the tree was hidden. That set of
464      // lanes is a superset of the lanes we started rendering with.
465      //
466      // So we'll throw out the current work and restart.
467      prepareFreshStack(root, NoLanes);
468    } else if (exitStatus !== RootIncomplete) {
469      if (exitStatus === RootErrored) {
470        executionContext |= RetryAfterError; // If an error occurred during hydration,
471        // discard server response and fall back to client side render.
472
473        if (root.hydrate) {
474          root.hydrate = false;
475          clearContainer(root.containerInfo);
476        } // If something threw an error, try rendering one more time. We'll render
477        // synchronously to block concurrent data mutations, and we'll includes
478        // all pending updates are included. If it still fails after the second
479        // attempt, we'll give up and commit the resulting tree.
480
481
482        lanes = getLanesToRetrySynchronouslyOnError(root);
483
484        if (lanes !== NoLanes) {
485          exitStatus = renderRootSync(root, lanes);
486        }
487      }
488
489      if (exitStatus === RootFatalErrored) {
490        var fatalError = workInProgressRootFatalError;
491        prepareFreshStack(root, NoLanes);
492        markRootSuspended$1(root, lanes);
493        ensureRootIsScheduled(root, now());
494        throw fatalError;
495      } // We now have a consistent tree. The next step is either to commit it,
496      // or, if something suspended, wait to commit it after a timeout.
497
498
499      var finishedWork = root.current.alternate;
500      root.finishedWork = finishedWork;
501      root.finishedLanes = lanes;
502      finishConcurrentRender(root, exitStatus, lanes);
503    }
504
505    ensureRootIsScheduled(root, now());
506
507    if (root.callbackNode === originalCallbackNode) {
508      // The task node scheduled for this root is the same one that's
509      // currently executed. Need to return a continuation.
510      return performConcurrentWorkOnRoot.bind(null, root);
511    }
512
513    return null;
514  }
515
516  function finishConcurrentRender(root, exitStatus, lanes) {
517    switch (exitStatus) {
518      case RootIncomplete:
519      case RootFatalErrored:
520        {
521          {
522            {
523              throw Error( "Root did not complete. This is a bug in React." );
524            }
525          }
526        }
527      // Flow knows about invariant, so it complains if I add a break
528      // statement, but eslint doesn't know about invariant, so it complains
529      // if I do. eslint-disable-next-line no-fallthrough
530
531      case RootErrored:
532        {
533          // We should have already attempted to retry this tree. If we reached
534          // this point, it errored again. Commit it.
535          commitRoot(root);
536          break;
537        }
538
539      case RootSuspended:
540        {
541          markRootSuspended$1(root, lanes); // We have an acceptable loading state. We need to figure out if we
542          // should immediately commit it or wait a bit.
543
544          if (includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope
545          !shouldForceFlushFallbacksInDEV()) {
546            // This render only included retries, no updates. Throttle committing
547            // retries so that we don't show too many loading states too quickly.
548            var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now(); // Don't bother with a very short suspense time.
549
550            if (msUntilTimeout > 10) {
551              var nextLanes = getNextLanes(root, NoLanes);
552
553              if (nextLanes !== NoLanes) {
554                // There's additional work on this root.
555                break;
556              }
557
558              var suspendedLanes = root.suspendedLanes;
559
560              if (!isSubsetOfLanes(suspendedLanes, lanes)) {
561                // We should prefer to render the fallback of at the last
562                // suspended level. Ping the last suspended level to try
563                // rendering it again.
564                // FIXME: What if the suspended lanes are Idle? Should not restart.
565                var eventTime = requestEventTime();
566                markRootPinged(root, suspendedLanes);
567                break;
568              } // The render is suspended, it hasn't timed out, and there's no
569              // lower priority work to do. Instead of committing the fallback
570              // immediately, wait for more data to arrive.
571
572
573              root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), msUntilTimeout);
574              break;
575            }
576          } // The work expired. Commit immediately.
577
578
579          commitRoot(root);
580          break;
581        }
582
583      case RootSuspendedWithDelay:
584        {
585          markRootSuspended$1(root, lanes);
586
587          if (includesOnlyTransitions(lanes)) {
588            // This is a transition, so we should exit without committing a
589            // placeholder and without scheduling a timeout. Delay indefinitely
590            // until we receive more data.
591            break;
592          }
593
594          if (!shouldForceFlushFallbacksInDEV()) {
595            // This is not a transition, but we did trigger an avoided state.
596            // Schedule a placeholder to display after a short delay, using the Just
597            // Noticeable Difference.
598            // TODO: Is the JND optimization worth the added complexity? If this is
599            // the only reason we track the event time, then probably not.
600            // Consider removing.
601            var mostRecentEventTime = getMostRecentEventTime(root, lanes);
602            var eventTimeMs = mostRecentEventTime;
603            var timeElapsedMs = now() - eventTimeMs;
604
605            var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time.
606
607
608            if (_msUntilTimeout > 10) {
609              // Instead of committing the fallback immediately, wait for more data
610              // to arrive.
611              root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout);
612              break;
613            }
614          } // Commit the placeholder.
615
616
617          commitRoot(root);
618          break;
619        }
620
621      case RootCompleted:
622        {
623          // The work completed. Ready to commit.
624          commitRoot(root);
625          break;
626        }
627
628      default:
629        {
630          {
631            {
632              throw Error( "Unknown root exit status." );
633            }
634          }
635        }
636    }
637  }
638
639  function markRootSuspended$1(root, suspendedLanes) {
640    // When suspending, we should always exclude lanes that were pinged or (more
641    // rarely, since we try to avoid it) updated during the render phase.
642    // TODO: Lol maybe there's a better way to factor this besides this
643    // obnoxiously named function :)
644    suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);
645    suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);
646    markRootSuspended(root, suspendedLanes);
647  } // This is the entry point for synchronous tasks that don't go
648  // through Scheduler
649
650
651  function performSyncWorkOnRoot(root) {
652    if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {
653      {
654        throw Error( "Should not already be working." );
655      }
656    }
657
658    flushPassiveEffects();
659    var lanes;
660    var exitStatus;
661
662    if (root === workInProgressRoot && includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)) {
663      // There's a partial tree, and at least one of its lanes has expired. Finish
664      // rendering it before rendering the rest of the expired work.
665      lanes = workInProgressRootRenderLanes;
666      exitStatus = renderRootSync(root, lanes);
667
668      if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {
669        // The render included lanes that were updated during the render phase.
670        // For example, when unhiding a hidden tree, we include all the lanes
671        // that were previously skipped when the tree was hidden. That set of
672        // lanes is a superset of the lanes we started rendering with.
673        //
674        // Note that this only happens when part of the tree is rendered
675        // concurrently. If the whole tree is rendered synchronously, then there
676        // are no interleaved events.
677        lanes = getNextLanes(root, lanes);
678        exitStatus = renderRootSync(root, lanes);
679      }
680    } else {
681      lanes = getNextLanes(root, NoLanes);
682      exitStatus = renderRootSync(root, lanes);
683    }
684
685    if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
686      executionContext |= RetryAfterError; // If an error occurred during hydration,
687      // discard server response and fall back to client side render.
688
689      if (root.hydrate) {
690        root.hydrate = false;
691        clearContainer(root.containerInfo);
692      } // If something threw an error, try rendering one more time. We'll render
693      // synchronously to block concurrent data mutations, and we'll includes
694      // all pending updates are included. If it still fails after the second
695      // attempt, we'll give up and commit the resulting tree.
696
697
698      lanes = getLanesToRetrySynchronouslyOnError(root);
699
700      if (lanes !== NoLanes) {
701        exitStatus = renderRootSync(root, lanes);
702      }
703    }
704
705    if (exitStatus === RootFatalErrored) {
706      var fatalError = workInProgressRootFatalError;
707      prepareFreshStack(root, NoLanes);
708      markRootSuspended$1(root, lanes);
709      ensureRootIsScheduled(root, now());
710      throw fatalError;
711    } // We now have a consistent tree. Because this is a sync render, we
712    // will commit it even if something suspended.
713
714
715    var finishedWork = root.current.alternate;
716    root.finishedWork = finishedWork;
717    root.finishedLanes = lanes;
718    commitRoot(root); // Before exiting, make sure there's a callback scheduled for the next
719    // pending level.
720
721    ensureRootIsScheduled(root, now());
722    return null;
723  }
724
725  function flushRoot(root, lanes) {
726    markRootExpired(root, lanes);
727    ensureRootIsScheduled(root, now());
728
729    if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
730      resetRenderTimer();
731      flushSyncCallbackQueue();
732    }
733  }
734  function getExecutionContext() {
735    return executionContext;
736  }
737  // flush react事件
738  function flushDiscreteUpdates() {
739    // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.
740    // However, `act` uses `batchedUpdates`, so there's no way to distinguish
741    // those two cases. Need to fix this before exposing flushDiscreteUpdates
742    // as a public API.
743    if ((executionContext & (BatchedContext | RenderContext | CommitContext)) !== NoContext) {
744      {
745        if ((executionContext & RenderContext) !== NoContext) {
746          error('unstable_flushDiscreteUpdates: Cannot flush updates when React is ' + 'already rendering.');
747        }
748      } // We're already rendering, so we can't synchronously flush pending work.
749      // This is probably a nested event dispatch triggered by a lifecycle/effect,
750      // like `el.focus()`. Exit.
751
752
753      return;
754    }
755
756    flushPendingDiscreteUpdates(); // If the discrete updates scheduled passive effects, flush them now so that
757    // they fire before the next serial event.
758
759    flushPassiveEffects();
760  }
761
762  function flushPendingDiscreteUpdates() {
763    if (rootsWithPendingDiscreteUpdates !== null) {
764      // For each root with pending discrete updates, schedule a callback to
765      // immediately flush them.
766      var roots = rootsWithPendingDiscreteUpdates;
767      rootsWithPendingDiscreteUpdates = null;
768      roots.forEach(function (root) {
769        markDiscreteUpdatesExpired(root);
770        ensureRootIsScheduled(root, now());
771      });
772    } // Now flush the immediate queue.
773
774
775    flushSyncCallbackQueue();
776  }
777
778  function batchedUpdates$1(fn, a) {
779    var prevExecutionContext = executionContext;
780    executionContext |= BatchedContext;
781
782    try {
783      return fn(a);
784    } finally {
785      executionContext = prevExecutionContext;
786
787      if (executionContext === NoContext) {
788        // Flush the immediate callbacks that were scheduled during this batch
789        resetRenderTimer();
790        flushSyncCallbackQueue();
791      }
792    }
793  }
794  function batchedEventUpdates$1(fn, a) {
795    var prevExecutionContext = executionContext;
796    executionContext |= EventContext;
797
798    try {
799      return fn(a);
800    } finally {
801      executionContext = prevExecutionContext;
802
803      if (executionContext === NoContext) {
804        // Flush the immediate callbacks that were scheduled during this batch
805        resetRenderTimer();
806        flushSyncCallbackQueue();
807      }
808    }
809  }
810  function discreteUpdates$1(fn, a, b, c, d) {
811    var prevExecutionContext = executionContext;
812    executionContext |= DiscreteEventContext;
813
814    {
815      try {
816        return runWithPriority$1(UserBlockingPriority$2, fn.bind(null, a, b, c, d));
817      } finally {
818        executionContext = prevExecutionContext;
819
820        if (executionContext === NoContext) {
821          // Flush the immediate callbacks that were scheduled during this batch
822          resetRenderTimer();
823          flushSyncCallbackQueue();
824        }
825      }
826    }
827  }
828  // 非批量更新
829  function unbatchedUpdates(fn, a) {
830    var prevExecutionContext = executionContext;
831    executionContext &= ~BatchedContext;
832    executionContext |= LegacyUnbatchedContext;
833
834    try {
835      return fn(a);
836    } finally {
837      executionContext = prevExecutionContext;
838
839      if (executionContext === NoContext) {
840        // Flush the immediate callbacks that were scheduled during this batch
841        resetRenderTimer();
842        flushSyncCallbackQueue();
843      }
844    }
845  }
846  function flushSync(fn, a) {
847    var prevExecutionContext = executionContext;
848
849    if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {
850      {
851        error('flushSync was called from inside a lifecycle method. React cannot ' + 'flush when React is already rendering. Consider moving this call to ' + 'a scheduler task or micro task.');
852      }
853
854      return fn(a);
855    }
856
857    executionContext |= BatchedContext;
858
859    {
860      try {
861        if (fn) {
862          return runWithPriority$1(ImmediatePriority$1, fn.bind(null, a));
863        } else {
864          return undefined;
865        }
866      } finally {
867        executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch.
868        // Note that this will happen even if batchedUpdates is higher up
869        // the stack.
870
871        flushSyncCallbackQueue();
872      }
873    }
874  }
875  function flushControlled(fn) {
876    var prevExecutionContext = executionContext;
877    executionContext |= BatchedContext;
878
879    {
880      try {
881        runWithPriority$1(ImmediatePriority$1, fn);
882      } finally {
883        executionContext = prevExecutionContext;
884
885        if (executionContext === NoContext) {
886          // Flush the immediate callbacks that were scheduled during this batch
887          resetRenderTimer();
888          flushSyncCallbackQueue();
889        }
890      }
891    }
892  }
893  function pushRenderLanes(fiber, lanes) {
894    push(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);
895    subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);
896    workInProgressRootIncludedLanes = mergeLanes(workInProgressRootIncludedLanes, lanes);
897  }
898  function popRenderLanes(fiber) {
899    subtreeRenderLanes = subtreeRenderLanesCursor.current;
900    pop(subtreeRenderLanesCursor, fiber);
901  }
902
903  function prepareFreshStack(root, lanes) {
904    root.finishedWork = null;
905    root.finishedLanes = NoLanes;
906    var timeoutHandle = root.timeoutHandle;
907
908    if (timeoutHandle !== noTimeout) {
909      // The root previous suspended and scheduled a timeout to commit a fallback
910      // state. Now that we have additional work, cancel the timeout.
911      root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
912
913      cancelTimeout(timeoutHandle);
914    }
915
916    if (workInProgress !== null) {
917      var interruptedWork = workInProgress.return;
918
919      while (interruptedWork !== null) {
920        unwindInterruptedWork(interruptedWork);
921        interruptedWork = interruptedWork.return;
922      }
923    }
924
925    workInProgressRoot = root;
926    workInProgress = createWorkInProgress(root.current, null);
927    workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;
928    workInProgressRootExitStatus = RootIncomplete;
929    workInProgressRootFatalError = null;
930    workInProgressRootSkippedLanes = NoLanes;
931    workInProgressRootUpdatedLanes = NoLanes;
932    workInProgressRootPingedLanes = NoLanes;
933
934    {
935      spawnedWorkDuringRender = null;
936    }
937
938    {
939      ReactStrictModeWarnings.discardPendingWarnings();
940    }
941  }
942
943  function handleError(root, thrownValue) {
944    do {
945      var erroredWork = workInProgress;
946
947      try {
948        // Reset module-level state that was set during the render phase.
949        resetContextDependencies();
950        resetHooksAfterThrow();
951        resetCurrentFiber(); // TODO: I found and added this missing line while investigating a
952        // separate issue. Write a regression test using string refs.
953
954        ReactCurrentOwner$2.current = null;
955
956        if (erroredWork === null || erroredWork.return === null) {
957          // Expected to be working on a non-root fiber. This is a fatal error
958          // because there's no ancestor that can handle it; the root is
959          // supposed to capture all errors that weren't caught by an error
960          // boundary.
961          workInProgressRootExitStatus = RootFatalErrored;
962          workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next
963          // sibling, or the parent if there are no siblings. But since the root
964          // has no siblings nor a parent, we set it to null. Usually this is
965          // handled by `completeUnitOfWork` or `unwindWork`, but since we're
966          // intentionally not calling those, we need set it here.
967          // TODO: Consider calling `unwindWork` to pop the contexts.
968
969          workInProgress = null;
970          return;
971        }
972
973        if (enableProfilerTimer && erroredWork.mode & ProfileMode) {
974          // Record the time spent rendering before an error was thrown. This
975          // avoids inaccurate Profiler durations in the case of a
976          // suspended render.
977          stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);
978        }
979
980        throwException(root, erroredWork.return, erroredWork, thrownValue, workInProgressRootRenderLanes);
981        completeUnitOfWork(erroredWork);
982      } catch (yetAnotherThrownValue) {
983        // Something in the return path also threw.
984        thrownValue = yetAnotherThrownValue;
985
986        if (workInProgress === erroredWork && erroredWork !== null) {
987          // If this boundary has already errored, then we had trouble processing
988          // the error. Bubble it to the next boundary.
989          erroredWork = erroredWork.return;
990          workInProgress = erroredWork;
991        } else {
992          erroredWork = workInProgress;
993        }
994
995        continue;
996      } // Return to the normal work loop.
997
998
999      return;
1000    } while (true);
1001  }
1002
1003  function pushDispatcher() {
1004    var prevDispatcher = ReactCurrentDispatcher$2.current;
1005    ReactCurrentDispatcher$2.current = ContextOnlyDispatcher;
1006
1007    if (prevDispatcher === null) {
1008      // The React isomorphic package does not include a default dispatcher.
1009      // Instead the first renderer will lazily attach one, in order to give
1010      // nicer error messages.
1011      return ContextOnlyDispatcher;
1012    } else {
1013      return prevDispatcher;
1014    }
1015  }
1016
1017  function popDispatcher(prevDispatcher) {
1018    ReactCurrentDispatcher$2.current = prevDispatcher;
1019  }
1020
1021  function pushInteractions(root) {
1022    {
1023      var prevInteractions = __interactionsRef.current;
1024      __interactionsRef.current = root.memoizedInteractions;
1025      return prevInteractions;
1026    }
1027  }
1028
1029  function popInteractions(prevInteractions) {
1030    {
1031      __interactionsRef.current = prevInteractions;
1032    }
1033  }
1034
1035  function markCommitTimeOfFallback() {
1036    globalMostRecentFallbackTime = now();
1037  }
1038  function markSkippedUpdateLanes(lane) {
1039    workInProgressRootSkippedLanes = mergeLanes(lane, workInProgressRootSkippedLanes);
1040  }
1041  function renderDidSuspend() {
1042    if (workInProgressRootExitStatus === RootIncomplete) {
1043      workInProgressRootExitStatus = RootSuspended;
1044    }
1045  }
1046  function renderDidSuspendDelayIfPossible() {
1047    if (workInProgressRootExitStatus === RootIncomplete || workInProgressRootExitStatus === RootSuspended) {
1048      workInProgressRootExitStatus = RootSuspendedWithDelay;
1049    } // Check if there are updates that we skipped tree that might have unblocked
1050    // this render.
1051
1052
1053    if (workInProgressRoot !== null && (includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootUpdatedLanes))) {
1054      // Mark the current render as suspended so that we switch to working on
1055      // the updates that were skipped. Usually we only suspend at the end of
1056      // the render phase.
1057      // TODO: We should probably always mark the root as suspended immediately
1058      // (inside this function), since by suspending at the end of the render
1059      // phase introduces a potential mistake where we suspend lanes that were
1060      // pinged or updated while we were rendering.
1061      markRootSuspended$1(workInProgressRoot, workInProgressRootRenderLanes);
1062    }
1063  }
1064  function renderDidError() {
1065    if (workInProgressRootExitStatus !== RootCompleted) {
1066      workInProgressRootExitStatus = RootErrored;
1067    }
1068  } // Called during render to determine if anything has suspended.
1069  // Returns false if we're not sure.
1070
1071  function renderHasNotSuspendedYet() {
1072    // If something errored or completed, we can't really be sure,
1073    // so those are false.
1074    return workInProgressRootExitStatus === RootIncomplete;
1075  }
1076
1077  function renderRootSync(root, lanes) {
1078    var prevExecutionContext = executionContext;
1079    executionContext |= RenderContext;
1080    var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack
1081    // and prepare a fresh one. Otherwise we'll continue where we left off.
1082
1083    if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
1084      prepareFreshStack(root, lanes);
1085      startWorkOnPendingInteractions(root, lanes);
1086    }
1087
1088    var prevInteractions = pushInteractions(root);
1089
1090    {
1091      markRenderStarted(lanes);
1092    }
1093
1094    do {
1095      try {
1096        workLoopSync();
1097        break;
1098      } catch (thrownValue) {
1099        handleError(root, thrownValue);
1100      }
1101    } while (true);
1102
1103    resetContextDependencies();
1104
1105    {
1106      popInteractions(prevInteractions);
1107    }
1108
1109    executionContext = prevExecutionContext;
1110    popDispatcher(prevDispatcher);
1111
1112    if (workInProgress !== null) {
1113      // This is a sync render, so we should have finished the whole tree.
1114      {
1115        {
1116          throw Error( "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." );
1117        }
1118      }
1119    }
1120
1121    {
1122      markRenderStopped();
1123    } // Set this to null to indicate there's no in-progress render.
1124
1125
1126    workInProgressRoot = null;
1127    workInProgressRootRenderLanes = NoLanes;
1128    return workInProgressRootExitStatus;
1129  } // The work loop is an extremely hot path. Tell Closure not to inline it.
1130
1131  /** @noinline */
1132
1133
1134  function workLoopSync() {
1135    // Already timed out, so perform work without checking if we need to yield.
1136    while (workInProgress !== null) {
1137      performUnitOfWork(workInProgress);
1138    }
1139  }
1140
1141  function renderRootConcurrent(root, lanes) {
1142    var prevExecutionContext = executionContext;
1143    executionContext |= RenderContext;
1144    var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack
1145    // and prepare a fresh one. Otherwise we'll continue where we left off.
1146
1147    if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
1148      resetRenderTimer();
1149      prepareFreshStack(root, lanes);
1150      startWorkOnPendingInteractions(root, lanes);
1151    }
1152
1153    var prevInteractions = pushInteractions(root);
1154
1155    {
1156      markRenderStarted(lanes);
1157    }
1158
1159    do {
1160      try {
1161        workLoopConcurrent();
1162        break;
1163      } catch (thrownValue) {
1164        handleError(root, thrownValue);
1165      }
1166    } while (true);
1167
1168    resetContextDependencies();
1169
1170    {
1171      popInteractions(prevInteractions);
1172    }
1173
1174    popDispatcher(prevDispatcher);
1175    executionContext = prevExecutionContext;
1176
1177
1178    if (workInProgress !== null) {
1179      // Still work remaining.
1180      {
1181        markRenderYielded();
1182      }
1183
1184      return RootIncomplete;
1185    } else {
1186      // Completed the tree.
1187      {
1188        markRenderStopped();
1189      } // Set this to null to indicate there's no in-progress render.
1190
1191
1192      workInProgressRoot = null;
1193      workInProgressRootRenderLanes = NoLanes; // Return the final exit status.
1194
1195      return workInProgressRootExitStatus;
1196    }
1197  }
1198  /** @noinline */
1199
1200
1201  function workLoopConcurrent() {
1202    // Perform work until Scheduler asks us to yield
1203    while (workInProgress !== null && !shouldYield()) {
1204      performUnitOfWork(workInProgress);
1205    }
1206  }
1207
1208  function performUnitOfWork(unitOfWork) {
1209    // The current, flushed, state of this fiber is the alternate. Ideally
1210    // nothing should rely on this, but relying on it here means that we don't
1211    // need an additional field on the work in progress.
1212    var current = unitOfWork.alternate;
1213    setCurrentFiber(unitOfWork);
1214    var next;
1215
1216    if ( (unitOfWork.mode & ProfileMode) !== NoMode) {
1217      startProfilerTimer(unitOfWork);
1218      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);
1219      stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
1220    } else {
1221      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);
1222    }
1223
1224    resetCurrentFiber();
1225    unitOfWork.memoizedProps = unitOfWork.pendingProps;
1226
1227    if (next === null) {
1228      // If this doesn't spawn new work, complete the current work.
1229      completeUnitOfWork(unitOfWork);
1230    } else {
1231      workInProgress = next;
1232    }
1233
1234    ReactCurrentOwner$2.current = null;
1235  }
1236
1237  function completeUnitOfWork(unitOfWork) {
1238    // Attempt to complete the current unit of work, then move to the next
1239    // sibling. If there are no more siblings, return to the parent fiber.
1240    var completedWork = unitOfWork;
1241
1242    do {
1243      // The current, flushed, state of this fiber is the alternate. Ideally
1244      // nothing should rely on this, but relying on it here means that we don't
1245      // need an additional field on the work in progress.
1246      var current = completedWork.alternate;
1247      var returnFiber = completedWork.return; // Check if the work completed or if something threw.
1248
1249      if ((completedWork.flags & Incomplete) === NoFlags) {
1250        setCurrentFiber(completedWork);
1251        var next = void 0;
1252
1253        if ( (completedWork.mode & ProfileMode) === NoMode) {
1254          next = completeWork(current, completedWork, subtreeRenderLanes);
1255        } else {
1256          startProfilerTimer(completedWork);
1257          next = completeWork(current, completedWork, subtreeRenderLanes); // Update render duration assuming we didn't error.
1258
1259          stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
1260        }
1261
1262        resetCurrentFiber();
1263
1264        if (next !== null) {
1265          // Completing this fiber spawned new work. Work on that next.
1266          workInProgress = next;
1267          return;
1268        }
1269
1270        resetChildLanes(completedWork);
1271
1272        if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete
1273        (returnFiber.flags & Incomplete) === NoFlags) {
1274          // Append all the effects of the subtree and this fiber onto the effect
1275          // list of the parent. The completion order of the children affects the
1276          // side-effect order.
1277          if (returnFiber.firstEffect === null) {
1278            returnFiber.firstEffect = completedWork.firstEffect;
1279          }
1280
1281          if (completedWork.lastEffect !== null) {
1282            if (returnFiber.lastEffect !== null) {
1283              returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
1284            }
1285
1286            returnFiber.lastEffect = completedWork.lastEffect;
1287          } // If this fiber had side-effects, we append it AFTER the children's
1288          // side-effects. We can perform certain side-effects earlier if needed,
1289          // by doing multiple passes over the effect list. We don't want to
1290          // schedule our own side-effect on our own list because if end up
1291          // reusing children we'll schedule this effect onto itself since we're
1292          // at the end.
1293
1294
1295          var flags = completedWork.flags; // Skip both NoWork and PerformedWork tags when creating the effect
1296          // list. PerformedWork effect is read by React DevTools but shouldn't be
1297          // committed.
1298
1299          if (flags > PerformedWork) {
1300            if (returnFiber.lastEffect !== null) {
1301              returnFiber.lastEffect.nextEffect = completedWork;
1302            } else {
1303              returnFiber.firstEffect = completedWork;
1304            }
1305
1306            returnFiber.lastEffect = completedWork;
1307          }
1308        }
1309      } else {
1310        // This fiber did not complete because something threw. Pop values off
1311        // the stack without entering the complete phase. If this is a boundary,
1312        // capture values if possible.
1313        var _next = unwindWork(completedWork); // Because this fiber did not complete, don't reset its expiration time.
1314
1315
1316        if (_next !== null) {
1317          // If completing this work spawned new work, do that next. We'll come
1318          // back here again.
1319          // Since we're restarting, remove anything that is not a host effect
1320          // from the effect tag.
1321          _next.flags &= HostEffectMask;
1322          workInProgress = _next;
1323          return;
1324        }
1325
1326        if ( (completedWork.mode & ProfileMode) !== NoMode) {
1327          // Record the render duration for the fiber that errored.
1328          stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.
1329
1330          var actualDuration = completedWork.actualDuration;
1331          var child = completedWork.child;
1332
1333          while (child !== null) {
1334            actualDuration += child.actualDuration;
1335            child = child.sibling;
1336          }
1337
1338          completedWork.actualDuration = actualDuration;
1339        }
1340
1341        if (returnFiber !== null) {
1342          // Mark the parent fiber as incomplete and clear its effect list.
1343          returnFiber.firstEffect = returnFiber.lastEffect = null;
1344          returnFiber.flags |= Incomplete;
1345        }
1346      }
1347
1348      var siblingFiber = completedWork.sibling;
1349
1350      if (siblingFiber !== null) {
1351        // If there is more work to do in this returnFiber, do that next.
1352        workInProgress = siblingFiber;
1353        return;
1354      } // Otherwise, return to the parent
1355
1356
1357      completedWork = returnFiber; // Update the next thing we're working on in case something throws.
1358
1359      workInProgress = completedWork;
1360    } while (completedWork !== null); // We've reached the root.
1361
1362
1363    if (workInProgressRootExitStatus === RootIncomplete) {
1364      workInProgressRootExitStatus = RootCompleted;
1365    }
1366  }
1367
1368  function resetChildLanes(completedWork) {
1369    if ( // TODO: Move this check out of the hot path by moving `resetChildLanes`
1370    // to switch statement in `completeWork`.
1371    (completedWork.tag === LegacyHiddenComponent || completedWork.tag === OffscreenComponent) && completedWork.memoizedState !== null && !includesSomeLane(subtreeRenderLanes, OffscreenLane) && (completedWork.mode & ConcurrentMode) !== NoLanes) {
1372      // The children of this component are hidden. Don't bubble their
1373      // expiration times.
1374      return;
1375    }
1376
1377    var newChildLanes = NoLanes; // Bubble up the earliest expiration time.
1378
1379    if ( (completedWork.mode & ProfileMode) !== NoMode) {
1380      // In profiling mode, resetChildExpirationTime is also used to reset
1381      // profiler durations.
1382      var actualDuration = completedWork.actualDuration;
1383      var treeBaseDuration = completedWork.selfBaseDuration; // When a fiber is cloned, its actualDuration is reset to 0. This value will
1384      // only be updated if work is done on the fiber (i.e. it doesn't bailout).
1385      // When work is done, it should bubble to the parent's actualDuration. If
1386      // the fiber has not been cloned though, (meaning no work was done), then
1387      // this value will reflect the amount of time spent working on a previous
1388      // render. In that case it should not bubble. We determine whether it was
1389      // cloned by comparing the child pointer.
1390
1391      var shouldBubbleActualDurations = completedWork.alternate === null || completedWork.child !== completedWork.alternate.child;
1392      var child = completedWork.child;
1393
1394      while (child !== null) {
1395        newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));
1396
1397        if (shouldBubbleActualDurations) {
1398          actualDuration += child.actualDuration;
1399        }
1400
1401        treeBaseDuration += child.treeBaseDuration;
1402        child = child.sibling;
1403      }
1404
1405      var isTimedOutSuspense = completedWork.tag === SuspenseComponent && completedWork.memoizedState !== null;
1406
1407      if (isTimedOutSuspense) {
1408        // Don't count time spent in a timed out Suspense subtree as part of the base duration.
1409        var primaryChildFragment = completedWork.child;
1410
1411        if (primaryChildFragment !== null) {
1412          treeBaseDuration -= primaryChildFragment.treeBaseDuration;
1413        }
1414      }
1415
1416      completedWork.actualDuration = actualDuration;
1417      completedWork.treeBaseDuration = treeBaseDuration;
1418    } else {
1419      var _child = completedWork.child;
1420
1421      while (_child !== null) {
1422        newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));
1423        _child = _child.sibling;
1424      }
1425    }
1426
1427    completedWork.childLanes = newChildLanes;
1428  }
1429
1430  function commitRoot(root) {
1431    var renderPriorityLevel = getCurrentPriorityLevel();
1432    runWithPriority$1(ImmediatePriority$1, commitRootImpl.bind(null, root, renderPriorityLevel));
1433    return null;
1434  }
1435
1436  function commitRootImpl(root, renderPriorityLevel) {
1437    do {
1438      // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which
1439      // means `flushPassiveEffects` will sometimes result in additional
1440      // passive effects. So we need to keep flushing in a loop until there are
1441      // no more pending effects.
1442      // TODO: Might be better if `flushPassiveEffects` did not automatically
1443      // flush synchronous work at the end, to avoid factoring hazards like this.
1444      flushPassiveEffects();
1445    } while (rootWithPendingPassiveEffects !== null);
1446
1447    flushRenderPhaseStrictModeWarningsInDEV();
1448
1449    if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {
1450      {
1451        throw Error( "Should not already be working." );
1452      }
1453    }
1454
1455    var finishedWork = root.finishedWork;
1456    var lanes = root.finishedLanes;
1457
1458    {
1459      markCommitStarted(lanes);
1460    }
1461
1462    if (finishedWork === null) {
1463
1464      {
1465        markCommitStopped();
1466      }
1467
1468      return null;
1469    }
1470
1471    root.finishedWork = null;
1472    root.finishedLanes = NoLanes;
1473
1474    if (!(finishedWork !== root.current)) {
1475      {
1476        throw Error( "Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue." );
1477      }
1478    } // commitRoot never returns a continuation; it always finishes synchronously.
1479    // So we can clear these now to allow a new callback to be scheduled.
1480
1481
1482    root.callbackNode = null; // Update the first and last pending times on this root. The new first
1483    // pending time is whatever is left on the root fiber.
1484
1485    var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
1486    markRootFinished(root, remainingLanes); // Clear already finished discrete updates in case that a later call of
1487    // `flushDiscreteUpdates` starts a useless render pass which may cancels
1488    // a scheduled timeout.
1489
1490    if (rootsWithPendingDiscreteUpdates !== null) {
1491      if (!hasDiscreteLanes(remainingLanes) && rootsWithPendingDiscreteUpdates.has(root)) {
1492        rootsWithPendingDiscreteUpdates.delete(root);
1493      }
1494    }
1495
1496    if (root === workInProgressRoot) {
1497      // We can reset these now that they are finished.
1498      workInProgressRoot = null;
1499      workInProgress = null;
1500      workInProgressRootRenderLanes = NoLanes;
1501    } // Get the list of effects.
1502
1503
1504    var firstEffect;
1505
1506    if (finishedWork.flags > PerformedWork) {
1507      // A fiber's effect list consists only of its children, not itself. So if
1508      // the root has an effect, we need to add it to the end of the list. The
1509      // resulting list is the set that would belong to the root's parent, if it
1510      // had one; that is, all the effects in the tree including the root.
1511      if (finishedWork.lastEffect !== null) {
1512        finishedWork.lastEffect.nextEffect = finishedWork;
1513        firstEffect = finishedWork.firstEffect;
1514      } else {
1515        firstEffect = finishedWork;
1516      }
1517    } else {
1518      // There is no effect on the root.
1519      firstEffect = finishedWork.firstEffect;
1520    }
1521
1522    if (firstEffect !== null) {
1523
1524      var prevExecutionContext = executionContext;
1525      executionContext |= CommitContext;
1526      var prevInteractions = pushInteractions(root); // Reset this to null before calling lifecycles
1527
1528      ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass
1529      // of the effect list for each phase: all mutation effects come before all
1530      // layout effects, and so on.
1531      // The first phase a "before mutation" phase. We use this phase to read the
1532      // state of the host tree right before we mutate it. This is where
1533      // getSnapshotBeforeUpdate is called.
1534
1535      focusedInstanceHandle = prepareForCommit(root.containerInfo);
1536      shouldFireAfterActiveInstanceBlur = false;
1537      nextEffect = firstEffect;
1538
1539      do {
1540        {
1541          invokeGuardedCallback(null, commitBeforeMutationEffects, null);
1542
1543          if (hasCaughtError()) {
1544            if (!(nextEffect !== null)) {
1545              {
1546                throw Error( "Should be working on an effect." );
1547              }
1548            }
1549
1550            var error = clearCaughtError();
1551            captureCommitPhaseError(nextEffect, error);
1552            nextEffect = nextEffect.nextEffect;
1553          }
1554        }
1555      } while (nextEffect !== null); // We no longer need to track the active instance fiber
1556
1557
1558      focusedInstanceHandle = null;
1559
1560      {
1561        // Mark the current commit time to be shared by all Profilers in this
1562        // batch. This enables them to be grouped later.
1563        recordCommitTime();
1564      } // The next phase is the mutation phase, where we mutate the host tree.
1565
1566
1567      nextEffect = firstEffect;
1568
1569      do {
1570        {
1571          invokeGuardedCallback(null, commitMutationEffects, null, root, renderPriorityLevel);
1572
1573          if (hasCaughtError()) {
1574            if (!(nextEffect !== null)) {
1575              {
1576                throw Error( "Should be working on an effect." );
1577              }
1578            }
1579
1580            var _error = clearCaughtError();
1581
1582            captureCommitPhaseError(nextEffect, _error);
1583            nextEffect = nextEffect.nextEffect;
1584          }
1585        }
1586      } while (nextEffect !== null);
1587
1588      resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after
1589      // the mutation phase, so that the previous tree is still current during
1590      // componentWillUnmount, but before the layout phase, so that the finished
1591      // work is current during componentDidMount/Update.
1592
1593      root.current = finishedWork; // The next phase is the layout phase, where we call effects that read
1594      // the host tree after it's been mutated. The idiomatic use case for this is
1595      // layout, but class component lifecycles also fire here for legacy reasons.
1596
1597      nextEffect = firstEffect;
1598
1599      do {
1600        {
1601          invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);
1602
1603          if (hasCaughtError()) {
1604            if (!(nextEffect !== null)) {
1605              {
1606                throw Error( "Should be working on an effect." );
1607              }
1608            }
1609
1610            var _error2 = clearCaughtError();
1611
1612            captureCommitPhaseError(nextEffect, _error2);
1613            nextEffect = nextEffect.nextEffect;
1614          }
1615        }
1616      } while (nextEffect !== null);
1617
1618      nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an
1619      // opportunity to paint.
1620
1621      requestPaint();
1622
1623      {
1624        popInteractions(prevInteractions);
1625      }
1626
1627      executionContext = prevExecutionContext;
1628    } else {
1629      // No effects.
1630      root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were
1631      // no effects.
1632      // TODO: Maybe there's a better way to report this.
1633
1634      {
1635        recordCommitTime();
1636      }
1637    }
1638
1639    var rootDidHavePassiveEffects = rootDoesHavePassiveEffects;
1640
1641    if (rootDoesHavePassiveEffects) {
1642      // This commit has passive effects. Stash a reference to them. But don't
1643      // schedule a callback until after flushing layout work.
1644      rootDoesHavePassiveEffects = false;
1645      rootWithPendingPassiveEffects = root;
1646      pendingPassiveEffectsLanes = lanes;
1647      pendingPassiveEffectsRenderPriority = renderPriorityLevel;
1648    } else {
1649      // We are done with the effect chain at this point so let's clear the
1650      // nextEffect pointers to assist with GC. If we have passive effects, we'll
1651      // clear this in flushPassiveEffects.
1652      nextEffect = firstEffect;
1653
1654      while (nextEffect !== null) {
1655        var nextNextEffect = nextEffect.nextEffect;
1656        nextEffect.nextEffect = null;
1657
1658        if (nextEffect.flags & Deletion) {
1659          detachFiberAfterEffects(nextEffect);
1660        }
1661
1662        nextEffect = nextNextEffect;
1663      }
1664    } // Read this again, since an effect might have updated it
1665
1666
1667    remainingLanes = root.pendingLanes; // Check if there's remaining work on this root
1668
1669    if (remainingLanes !== NoLanes) {
1670      {
1671        if (spawnedWorkDuringRender !== null) {
1672          var expirationTimes = spawnedWorkDuringRender;
1673          spawnedWorkDuringRender = null;
1674
1675          for (var i = 0; i < expirationTimes.length; i++) {
1676            scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions);
1677          }
1678        }
1679
1680        schedulePendingInteractions(root, remainingLanes);
1681      }
1682    } else {
1683      // If there's no remaining work, we can clear the set of already failed
1684      // error boundaries.
1685      legacyErrorBoundariesThatAlreadyFailed = null;
1686    }
1687
1688    {
1689      if (!rootDidHavePassiveEffects) {
1690        // If there are no passive effects, then we can complete the pending interactions.
1691        // Otherwise, we'll wait until after the passive effects are flushed.
1692        // Wait to do this until after remaining work has been scheduled,
1693        // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.
1694        finishPendingInteractions(root, lanes);
1695      }
1696    }
1697
1698    if (remainingLanes === SyncLane) {
1699      // Count the number of times the root synchronously re-renders without
1700      // finishing. If there are too many, it indicates an infinite update loop.
1701      if (root === rootWithNestedUpdates) {
1702        nestedUpdateCount++;
1703      } else {
1704        nestedUpdateCount = 0;
1705        rootWithNestedUpdates = root;
1706      }
1707    } else {
1708      nestedUpdateCount = 0;
1709    }
1710
1711    onCommitRoot(finishedWork.stateNode, renderPriorityLevel);
1712
1713    {
1714      onCommitRoot$1();
1715    } // Always call this before exiting `commitRoot`, to ensure that any
1716    // additional work on this root is scheduled.
1717
1718
1719    ensureRootIsScheduled(root, now());
1720
1721    if (hasUncaughtError) {
1722      hasUncaughtError = false;
1723      var _error3 = firstUncaughtError;
1724      firstUncaughtError = null;
1725      throw _error3;
1726    }
1727
1728    if ((executionContext & LegacyUnbatchedContext) !== NoContext) {
1729
1730      {
1731        markCommitStopped();
1732      } // This is a legacy edge case. We just committed the initial mount of
1733      // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired
1734      // synchronously, but layout updates should be deferred until the end
1735      // of the batch.
1736
1737
1738      return null;
1739    } // If layout work was scheduled, flush it now.
1740
1741
1742    flushSyncCallbackQueue();
1743
1744    {
1745      markCommitStopped();
1746    }
1747
1748    return null;
1749  }
1750
1751  function commitBeforeMutationEffects() {
1752    while (nextEffect !== null) {
1753      var current = nextEffect.alternate;
1754
1755      if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
1756        if ((nextEffect.flags & Deletion) !== NoFlags) {
1757          if (doesFiberContain(nextEffect, focusedInstanceHandle)) {
1758            shouldFireAfterActiveInstanceBlur = true;
1759          }
1760        } else {
1761          // TODO: Move this out of the hot path using a dedicated effect tag.
1762          if (nextEffect.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, nextEffect) && doesFiberContain(nextEffect, focusedInstanceHandle)) {
1763            shouldFireAfterActiveInstanceBlur = true;
1764          }
1765        }
1766      }
1767
1768      var flags = nextEffect.flags;
1769
1770      if ((flags & Snapshot) !== NoFlags) {
1771        setCurrentFiber(nextEffect);
1772        commitBeforeMutationLifeCycles(current, nextEffect);
1773        resetCurrentFiber();
1774      }
1775
1776      if ((flags & Passive) !== NoFlags) {
1777        // If there are passive effects, schedule a callback to flush at
1778        // the earliest opportunity.
1779        if (!rootDoesHavePassiveEffects) {
1780          rootDoesHavePassiveEffects = true;
1781          scheduleCallback(NormalPriority$1, function () {
1782            flushPassiveEffects();
1783            return null;
1784          });
1785        }
1786      }
1787
1788      nextEffect = nextEffect.nextEffect;
1789    }
1790  }
1791
1792  function commitMutationEffects(root, renderPriorityLevel) {
1793    // TODO: Should probably move the bulk of this function to commitWork.
1794    while (nextEffect !== null) {
1795      setCurrentFiber(nextEffect);
1796      var flags = nextEffect.flags;
1797
1798      if (flags & ContentReset) {
1799        commitResetTextContent(nextEffect);
1800      }
1801
1802      if (flags & Ref) {
1803        var current = nextEffect.alternate;
1804
1805        if (current !== null) {
1806          commitDetachRef(current);
1807        }
1808      } // The following switch statement is only concerned about placement,
1809      // updates, and deletions. To avoid needing to add a case for every possible
1810      // bitmap value, we remove the secondary effects from the effect tag and
1811      // switch on that value.
1812
1813
1814      var primaryFlags = flags & (Placement | Update | Deletion | Hydrating);
1815
1816      switch (primaryFlags) {
1817        case Placement:
1818          {
1819            commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is
1820            // inserted, before any life-cycles like componentDidMount gets called.
1821            // TODO: findDOMNode doesn't rely on this any more but isMounted does
1822            // and isMounted is deprecated anyway so we should be able to kill this.
1823
1824            nextEffect.flags &= ~Placement;
1825            break;
1826          }
1827
1828        case PlacementAndUpdate:
1829          {
1830            // Placement
1831            commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is
1832            // inserted, before any life-cycles like componentDidMount gets called.
1833
1834            nextEffect.flags &= ~Placement; // Update
1835
1836            var _current = nextEffect.alternate;
1837            commitWork(_current, nextEffect);
1838            break;
1839          }
1840
1841        case Hydrating:
1842          {
1843            nextEffect.flags &= ~Hydrating;
1844            break;
1845          }
1846
1847        case HydratingAndUpdate:
1848          {
1849            nextEffect.flags &= ~Hydrating; // Update
1850
1851            var _current2 = nextEffect.alternate;
1852            commitWork(_current2, nextEffect);
1853            break;
1854          }
1855
1856        case Update:
1857          {
1858            var _current3 = nextEffect.alternate;
1859            commitWork(_current3, nextEffect);
1860            break;
1861          }
1862
1863        case Deletion:
1864          {
1865            commitDeletion(root, nextEffect);
1866            break;
1867          }
1868      }
1869
1870      resetCurrentFiber();
1871      nextEffect = nextEffect.nextEffect;
1872    }
1873  }
1874
1875  function commitLayoutEffects(root, committedLanes) {
1876
1877    {
1878      markLayoutEffectsStarted(committedLanes);
1879    } // TODO: Should probably move the bulk of this function to commitWork.
1880
1881
1882    while (nextEffect !== null) {
1883      setCurrentFiber(nextEffect);
1884      var flags = nextEffect.flags;
1885
1886      if (flags & (Update | Callback)) {
1887        var current = nextEffect.alternate;
1888        commitLifeCycles(root, current, nextEffect);
1889      }
1890
1891      {
1892        if (flags & Ref) {
1893          commitAttachRef(nextEffect);
1894        }
1895      }
1896
1897      resetCurrentFiber();
1898      nextEffect = nextEffect.nextEffect;
1899    }
1900
1901    {
1902      markLayoutEffectsStopped();
1903    }
1904  }
1905
1906  function flushPassiveEffects() {
1907    // Returns whether passive effects were flushed.
1908    if (pendingPassiveEffectsRenderPriority !== NoPriority$1) {
1909      var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority$1 ? NormalPriority$1 : pendingPassiveEffectsRenderPriority;
1910      pendingPassiveEffectsRenderPriority = NoPriority$1;
1911
1912      {
1913        return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl);
1914      }
1915    }
1916
1917    return false;
1918  }
1919  function enqueuePendingPassiveHookEffectMount(fiber, effect) {
1920    pendingPassiveHookEffectsMount.push(effect, fiber);
1921
1922    if (!rootDoesHavePassiveEffects) {
1923      rootDoesHavePassiveEffects = true;
1924      scheduleCallback(NormalPriority$1, function () {
1925        flushPassiveEffects();
1926        return null;
1927      });
1928    }
1929  }
1930  function enqueuePendingPassiveHookEffectUnmount(fiber, effect) {
1931    pendingPassiveHookEffectsUnmount.push(effect, fiber);
1932
1933    {
1934      fiber.flags |= PassiveUnmountPendingDev;
1935      var alternate = fiber.alternate;
1936
1937      if (alternate !== null) {
1938        alternate.flags |= PassiveUnmountPendingDev;
1939      }
1940    }
1941
1942    if (!rootDoesHavePassiveEffects) {
1943      rootDoesHavePassiveEffects = true;
1944      scheduleCallback(NormalPriority$1, function () {
1945        flushPassiveEffects();
1946        return null;
1947      });
1948    }
1949  }
1950
1951  function invokePassiveEffectCreate(effect) {
1952    var create = effect.create;
1953    effect.destroy = create();
1954  }
1955
1956  function flushPassiveEffectsImpl() {
1957    if (rootWithPendingPassiveEffects === null) {
1958      return false;
1959    }
1960
1961    var root = rootWithPendingPassiveEffects;
1962    var lanes = pendingPassiveEffectsLanes;
1963    rootWithPendingPassiveEffects = null;
1964    pendingPassiveEffectsLanes = NoLanes;
1965
1966    if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {
1967      {
1968        throw Error( "Cannot flush passive effects while already rendering." );
1969      }
1970    }
1971
1972    {
1973      markPassiveEffectsStarted(lanes);
1974    }
1975
1976    {
1977      isFlushingPassiveEffects = true;
1978    }
1979
1980    var prevExecutionContext = executionContext;
1981    executionContext |= CommitContext;
1982    var prevInteractions = pushInteractions(root); // It's important that ALL pending passive effect destroy functions are called
1983    // before ANY passive effect create functions are called.
1984    // Otherwise effects in sibling components might interfere with each other.
1985    // e.g. a destroy function in one component may unintentionally override a ref
1986    // value set by a create function in another component.
1987    // Layout effects have the same constraint.
1988    // First pass: Destroy stale passive effects.
1989
1990    var unmountEffects = pendingPassiveHookEffectsUnmount;
1991    pendingPassiveHookEffectsUnmount = [];
1992
1993    for (var i = 0; i < unmountEffects.length; i += 2) {
1994      var _effect = unmountEffects[i];
1995      var fiber = unmountEffects[i + 1];
1996      var destroy = _effect.destroy;
1997      _effect.destroy = undefined;
1998
1999      {
2000        fiber.flags &= ~PassiveUnmountPendingDev;
2001        var alternate = fiber.alternate;
2002
2003        if (alternate !== null) {
2004          alternate.flags &= ~PassiveUnmountPendingDev;
2005        }
2006      }
2007
2008      if (typeof destroy === 'function') {
2009        {
2010          setCurrentFiber(fiber);
2011
2012          {
2013            invokeGuardedCallback(null, destroy, null);
2014          }
2015
2016          if (hasCaughtError()) {
2017            if (!(fiber !== null)) {
2018              {
2019                throw Error( "Should be working on an effect." );
2020              }
2021            }
2022
2023            var error = clearCaughtError();
2024            captureCommitPhaseError(fiber, error);
2025          }
2026
2027          resetCurrentFiber();
2028        }
2029      }
2030    } // Second pass: Create new passive effects.
2031
2032
2033    var mountEffects = pendingPassiveHookEffectsMount;
2034    pendingPassiveHookEffectsMount = [];
2035
2036    for (var _i = 0; _i < mountEffects.length; _i += 2) {
2037      var _effect2 = mountEffects[_i];
2038      var _fiber = mountEffects[_i + 1];
2039
2040      {
2041        setCurrentFiber(_fiber);
2042
2043        {
2044          invokeGuardedCallback(null, invokePassiveEffectCreate, null, _effect2);
2045        }
2046
2047        if (hasCaughtError()) {
2048          if (!(_fiber !== null)) {
2049            {
2050              throw Error( "Should be working on an effect." );
2051            }
2052          }
2053
2054          var _error4 = clearCaughtError();
2055
2056          captureCommitPhaseError(_fiber, _error4);
2057        }
2058
2059        resetCurrentFiber();
2060      }
2061    } // Note: This currently assumes there are no passive effects on the root fiber
2062    // because the root is not part of its own effect list.
2063    // This could change in the future.
2064
2065
2066    var effect = root.current.firstEffect;
2067
2068    while (effect !== null) {
2069      var nextNextEffect = effect.nextEffect; // Remove nextEffect pointer to assist GC
2070
2071      effect.nextEffect = null;
2072
2073      if (effect.flags & Deletion) {
2074        detachFiberAfterEffects(effect);
2075      }
2076
2077      effect = nextNextEffect;
2078    }
2079
2080    {
2081      popInteractions(prevInteractions);
2082      finishPendingInteractions(root, lanes);
2083    }
2084
2085    {
2086      isFlushingPassiveEffects = false;
2087    }
2088
2089    {
2090      markPassiveEffectsStopped();
2091    }
2092
2093    executionContext = prevExecutionContext;
2094    flushSyncCallbackQueue(); // If additional passive effects were scheduled, increment a counter. If this
2095    // exceeds the limit, we'll fire a warning.
2096
2097    nestedPassiveUpdateCount = rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;
2098    return true;
2099  }
2100
2101  function isAlreadyFailedLegacyErrorBoundary(instance) {
2102    return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance);
2103  }
2104  function markLegacyErrorBoundaryAsFailed(instance) {
2105    if (legacyErrorBoundariesThatAlreadyFailed === null) {
2106      legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);
2107    } else {
2108      legacyErrorBoundariesThatAlreadyFailed.add(instance);
2109    }
2110  }
2111
2112  function prepareToThrowUncaughtError(error) {
2113    if (!hasUncaughtError) {
2114      hasUncaughtError = true;
2115      firstUncaughtError = error;
2116    }
2117  }
2118
2119  var onUncaughtError = prepareToThrowUncaughtError;
2120
2121  function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) {
2122    var errorInfo = createCapturedValue(error, sourceFiber);
2123    var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane);
2124    enqueueUpdate(rootFiber, update);
2125    var eventTime = requestEventTime();
2126    var root = markUpdateLaneFromFiberToRoot(rootFiber, SyncLane);
2127
2128    if (root !== null) {
2129      markRootUpdated(root, SyncLane, eventTime);
2130      ensureRootIsScheduled(root, eventTime);
2131      schedulePendingInteractions(root, SyncLane);
2132    }
2133  }
2134
2135  function captureCommitPhaseError(sourceFiber, error) {
2136    if (sourceFiber.tag === HostRoot) {
2137      // Error was thrown at the root. There is no parent, so the root
2138      // itself should capture it.
2139      captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);
2140      return;
2141    }
2142
2143    var fiber = sourceFiber.return;
2144
2145    while (fiber !== null) {
2146      if (fiber.tag === HostRoot) {
2147        captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);
2148        return;
2149      } else if (fiber.tag === ClassComponent) {
2150        var ctor = fiber.type;
2151        var instance = fiber.stateNode;
2152
2153        if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {
2154          var errorInfo = createCapturedValue(error, sourceFiber);
2155          var update = createClassErrorUpdate(fiber, errorInfo, SyncLane);
2156          enqueueUpdate(fiber, update);
2157          var eventTime = requestEventTime();
2158          var root = markUpdateLaneFromFiberToRoot(fiber, SyncLane);
2159
2160          if (root !== null) {
2161            markRootUpdated(root, SyncLane, eventTime);
2162            ensureRootIsScheduled(root, eventTime);
2163            schedulePendingInteractions(root, SyncLane);
2164          } else {
2165            // This component has already been unmounted.
2166            // We can't schedule any follow up work for the root because the fiber is already unmounted,
2167            // but we can still call the log-only boundary so the error isn't swallowed.
2168            //
2169            // TODO This is only a temporary bandaid for the old reconciler fork.
2170            // We can delete this special case once the new fork is merged.
2171            if (typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {
2172              try {
2173                instance.componentDidCatch(error, errorInfo);
2174              } catch (errorToIgnore) {// TODO Ignore this error? Rethrow it?
2175                // This is kind of an edge case.
2176              }
2177            }
2178          }
2179
2180          return;
2181        }
2182      }
2183
2184      fiber = fiber.return;
2185    }
2186  }
2187  function pingSuspendedRoot(root, wakeable, pingedLanes) {
2188    var pingCache = root.pingCache;
2189
2190    if (pingCache !== null) {
2191      // The wakeable resolved, so we no longer need to memoize, because it will
2192      // never be thrown again.
2193      pingCache.delete(wakeable);
2194    }
2195
2196    var eventTime = requestEventTime();
2197    markRootPinged(root, pingedLanes);
2198
2199    if (workInProgressRoot === root && isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)) {
2200      // Received a ping at the same priority level at which we're currently
2201      // rendering. We might want to restart this render. This should mirror
2202      // the logic of whether or not a root suspends once it completes.
2203      // TODO: If we're rendering sync either due to Sync, Batched or expired,
2204      // we should probably never restart.
2205      // If we're suspended with delay, or if it's a retry, we'll always suspend
2206      // so we can always restart.
2207      if (workInProgressRootExitStatus === RootSuspendedWithDelay || workInProgressRootExitStatus === RootSuspended && includesOnlyRetries(workInProgressRootRenderLanes) && now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) {
2208        // Restart from the root.
2209        prepareFreshStack(root, NoLanes);
2210      } else {
2211        // Even though we can't restart right now, we might get an
2212        // opportunity later. So we mark this render as having a ping.
2213        workInProgressRootPingedLanes = mergeLanes(workInProgressRootPingedLanes, pingedLanes);
2214      }
2215    }
2216
2217    ensureRootIsScheduled(root, eventTime);
2218    schedulePendingInteractions(root, pingedLanes);
2219  }
2220
2221  function retryTimedOutBoundary(boundaryFiber, retryLane) {
2222    // The boundary fiber (a Suspense component or SuspenseList component)
2223    // previously was rendered in its fallback state. One of the promises that
2224    // suspended it has resolved, which means at least part of the tree was
2225    // likely unblocked. Try rendering again, at a new expiration time.
2226    if (retryLane === NoLane) {
2227      retryLane = requestRetryLane(boundaryFiber);
2228    } // TODO: Special case idle priority?
2229
2230
2231    var eventTime = requestEventTime();
2232    var root = markUpdateLaneFromFiberToRoot(boundaryFiber, retryLane);
2233
2234    if (root !== null) {
2235      markRootUpdated(root, retryLane, eventTime);
2236      ensureRootIsScheduled(root, eventTime);
2237      schedulePendingInteractions(root, retryLane);
2238    }
2239  }
2240
2241  function retryDehydratedSuspenseBoundary(boundaryFiber) {
2242    var suspenseState = boundaryFiber.memoizedState;
2243    var retryLane = NoLane;
2244
2245    if (suspenseState !== null) {
2246      retryLane = suspenseState.retryLane;
2247    }
2248
2249    retryTimedOutBoundary(boundaryFiber, retryLane);
2250  }
2251  function resolveRetryWakeable(boundaryFiber, wakeable) {
2252    var retryLane = NoLane; // Default
2253
2254    var retryCache;
2255
2256    {
2257      switch (boundaryFiber.tag) {
2258        case SuspenseComponent:
2259          retryCache = boundaryFiber.stateNode;
2260          var suspenseState = boundaryFiber.memoizedState;
2261
2262          if (suspenseState !== null) {
2263            retryLane = suspenseState.retryLane;
2264          }
2265
2266          break;
2267
2268        case SuspenseListComponent:
2269          retryCache = boundaryFiber.stateNode;
2270          break;
2271
2272        default:
2273          {
2274            {
2275              throw Error( "Pinged unknown suspense boundary type. This is probably a bug in React." );
2276            }
2277          }
2278
2279      }
2280    }
2281
2282    if (retryCache !== null) {
2283      // The wakeable resolved, so we no longer need to memoize, because it will
2284      // never be thrown again.
2285      retryCache.delete(wakeable);
2286    }
2287
2288    retryTimedOutBoundary(boundaryFiber, retryLane);
2289  } // Computes the next Just Noticeable Difference (JND) boundary.
2290  // The theory is that a person can't tell the difference between small differences in time.
2291  // Therefore, if we wait a bit longer than necessary that won't translate to a noticeable
2292  // difference in the experience. However, waiting for longer might mean that we can avoid
2293  // showing an intermediate loading state. The longer we have already waited, the harder it
2294  // is to tell small differences in time. Therefore, the longer we've already waited,
2295  // the longer we can wait additionally. At some point we have to give up though.
2296  // We pick a train model where the next boundary commits at a consistent schedule.
2297  // These particular numbers are vague estimates. We expect to adjust them based on research.
2298
2299  function jnd(timeElapsed) {
2300    return timeElapsed < 120 ? 120 : timeElapsed < 480 ? 480 : timeElapsed < 1080 ? 1080 : timeElapsed < 1920 ? 1920 : timeElapsed < 3000 ? 3000 : timeElapsed < 4320 ? 4320 : ceil(timeElapsed / 1960) * 1960;
2301  }
2302
2303  function checkForNestedUpdates() {
2304    if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
2305      nestedUpdateCount = 0;
2306      rootWithNestedUpdates = null;
2307
2308      {
2309        {
2310          throw Error( "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." );
2311        }
2312      }
2313    }
2314
2315    {
2316      if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {
2317        nestedPassiveUpdateCount = 0;
2318
2319        error('Maximum update depth exceeded. This can happen when a component ' + "calls setState inside useEffect, but useEffect either doesn't " + 'have a dependency array, or one of the dependencies changes on ' + 'every render.');
2320      }
2321    }
2322  }
2323
2324  function flushRenderPhaseStrictModeWarningsInDEV() {
2325    {
2326      ReactStrictModeWarnings.flushLegacyContextWarning();
2327
2328      {
2329        ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();
2330      }
2331    }
2332  }
2333
2334  var didWarnStateUpdateForNotYetMountedComponent = null;
2335
2336  function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {
2337    {
2338      if ((executionContext & RenderContext) !== NoContext) {
2339        // We let the other warning about render phase updates deal with this one.
2340        return;
2341      }
2342
2343      if (!(fiber.mode & (BlockingMode | ConcurrentMode))) {
2344        return;
2345      }
2346
2347      var tag = fiber.tag;
2348
2349      if (tag !== IndeterminateComponent && tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {
2350        // Only warn for user-defined components, not internal ones like Suspense.
2351        return;
2352      } // We show the whole stack but dedupe on the top component's name because
2353      // the problematic code almost always lies inside that component.
2354
2355
2356      var componentName = getComponentName(fiber.type) || 'ReactComponent';
2357
2358      if (didWarnStateUpdateForNotYetMountedComponent !== null) {
2359        if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {
2360          return;
2361        }
2362
2363        didWarnStateUpdateForNotYetMountedComponent.add(componentName);
2364      } else {
2365        didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);
2366      }
2367
2368      var previousFiber = current;
2369
2370      try {
2371        setCurrentFiber(fiber);
2372
2373        error("Can't perform a React state update on a component that hasn't mounted yet. " + 'This indicates that you have a side-effect in your render function that ' + 'asynchronously later calls tries to update the component. Move this work to ' + 'useEffect instead.');
2374      } finally {
2375        if (previousFiber) {
2376          setCurrentFiber(fiber);
2377        } else {
2378          resetCurrentFiber();
2379        }
2380      }
2381    }
2382  }
2383
2384  var didWarnStateUpdateForUnmountedComponent = null;
2385
2386  function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {
2387    {
2388      var tag = fiber.tag;
2389
2390      if (tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {
2391        // Only warn for user-defined components, not internal ones like Suspense.
2392        return;
2393      } // If there are pending passive effects unmounts for this Fiber,
2394      // we can assume that they would have prevented this update.
2395
2396
2397      if ((fiber.flags & PassiveUnmountPendingDev) !== NoFlags) {
2398        return;
2399      } // We show the whole stack but dedupe on the top component's name because
2400      // the problematic code almost always lies inside that component.
2401
2402
2403      var componentName = getComponentName(fiber.type) || 'ReactComponent';
2404
2405      if (didWarnStateUpdateForUnmountedComponent !== null) {
2406        if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {
2407          return;
2408        }
2409
2410        didWarnStateUpdateForUnmountedComponent.add(componentName);
2411      } else {
2412        didWarnStateUpdateForUnmountedComponent = new Set([componentName]);
2413      }
2414
2415      if (isFlushingPassiveEffects) ; else {
2416        var previousFiber = current;
2417
2418        try {
2419          setCurrentFiber(fiber);
2420
2421          error("Can't perform a React state update on an unmounted component. This " + 'is a no-op, but it indicates a memory leak in your application. To ' + 'fix, cancel all subscriptions and asynchronous tasks in %s.', tag === ClassComponent ? 'the componentWillUnmount method' : 'a useEffect cleanup function');
2422        } finally {
2423          if (previousFiber) {
2424            setCurrentFiber(fiber);
2425          } else {
2426            resetCurrentFiber();
2427          }
2428        }
2429      }
2430    }
2431  }
2432
2433  var beginWork$1;
2434
2435  {
2436    var dummyFiber = null;
2437
2438    beginWork$1 = function (current, unitOfWork, lanes) {
2439      // If a component throws an error, we replay it again in a synchronously
2440      // dispatched event, so that the debugger will treat it as an uncaught
2441      // error See ReactErrorUtils for more information.
2442      // Before entering the begin phase, copy the work-in-progress onto a dummy
2443      // fiber. If beginWork throws, we'll use this to reset the state.
2444      var originalWorkInProgressCopy = assignFiberPropertiesInDEV(dummyFiber, unitOfWork);
2445
2446      try {
2447        return beginWork(current, unitOfWork, lanes);
2448      } catch (originalError) {
2449        if (originalError !== null && typeof originalError === 'object' && typeof originalError.then === 'function') {
2450          // Don't replay promises. Treat everything else like an error.
2451          throw originalError;
2452        } // Keep this code in sync with handleError; any changes here must have
2453        // corresponding changes there.
2454
2455
2456        resetContextDependencies();
2457        resetHooksAfterThrow(); // Don't reset current debug fiber, since we're about to work on the
2458        // same fiber again.
2459        // Unwind the failed stack frame
2460
2461        unwindInterruptedWork(unitOfWork); // Restore the original properties of the fiber.
2462
2463        assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);
2464
2465        if ( unitOfWork.mode & ProfileMode) {
2466          // Reset the profiler timer.
2467          startProfilerTimer(unitOfWork);
2468        } // Run beginWork again.
2469
2470
2471        invokeGuardedCallback(null, beginWork, null, current, unitOfWork, lanes);
2472
2473        if (hasCaughtError()) {
2474          var replayError = clearCaughtError(); // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.
2475          // Rethrow this error instead of the original one.
2476
2477          throw replayError;
2478        } else {
2479          // This branch is reachable if the render phase is impure.
2480          throw originalError;
2481        }
2482      }
2483    };
2484  }
2485
2486  var didWarnAboutUpdateInRender = false;
2487  var didWarnAboutUpdateInRenderForAnotherComponent;
2488
2489  {
2490    didWarnAboutUpdateInRenderForAnotherComponent = new Set();
2491  }
2492
2493  function warnAboutRenderPhaseUpdatesInDEV(fiber) {
2494    {
2495      if (isRendering && (executionContext & RenderContext) !== NoContext && !getIsUpdatingOpaqueValueInRenderPhaseInDEV()) {
2496        switch (fiber.tag) {
2497          case FunctionComponent:
2498          case ForwardRef:
2499          case SimpleMemoComponent:
2500            {
2501              var renderingComponentName = workInProgress && getComponentName(workInProgress.type) || 'Unknown'; // Dedupe by the rendering component because it's the one that needs to be fixed.
2502
2503              var dedupeKey = renderingComponentName;
2504
2505              if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {
2506                didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);
2507                var setStateComponentName = getComponentName(fiber.type) || 'Unknown';
2508
2509                error('Cannot update a component (`%s`) while rendering a ' + 'different component (`%s`). To locate the bad setState() call inside `%s`, ' + 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName);
2510              }
2511
2512              break;
2513            }
2514
2515          case ClassComponent:
2516            {
2517              if (!didWarnAboutUpdateInRender) {
2518                error('Cannot update during an existing state transition (such as ' + 'within `render`). Render methods should be a pure ' + 'function of props and state.');
2519
2520                didWarnAboutUpdateInRender = true;
2521              }
2522
2523              break;
2524            }
2525        }
2526      }
2527    }
2528  } // a 'shared' variable that changes when act() opens/closes in tests.
2529
2530
2531  var IsThisRendererActing = {
2532    current: false
2533  };
2534  function warnIfNotScopedWithMatchingAct(fiber) {
2535    {
2536      if ( IsSomeRendererActing.current === true && IsThisRendererActing.current !== true) {
2537        var previousFiber = current;
2538
2539        try {
2540          setCurrentFiber(fiber);
2541
2542          error("It looks like you're using the wrong act() around your test interactions.\n" + 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' + '// for react-dom:\n' + // Break up imports to avoid accidentally parsing them as dependencies.
2543          'import {act} fr' + "om 'react-dom/test-utils';\n" + '// ...\n' + 'act(() => ...);\n\n' + '// for react-test-renderer:\n' + // Break up imports to avoid accidentally parsing them as dependencies.
2544          'import TestRenderer fr' + "om react-test-renderer';\n" + 'const {act} = TestRenderer;\n' + '// ...\n' + 'act(() => ...);');
2545        } finally {
2546          if (previousFiber) {
2547            setCurrentFiber(fiber);
2548          } else {
2549            resetCurrentFiber();
2550          }
2551        }
2552      }
2553    }
2554  }
2555  function warnIfNotCurrentlyActingEffectsInDEV(fiber) {
2556    {
2557      if ( (fiber.mode & StrictMode) !== NoMode && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {
2558        error('An update to %s ran an effect, but was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + '  /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentName(fiber.type));
2559      }
2560    }
2561  }
2562
2563  function warnIfNotCurrentlyActingUpdatesInDEV(fiber) {
2564    {
2565      if ( executionContext === NoContext && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {
2566        var previousFiber = current;
2567
2568        try {
2569          setCurrentFiber(fiber);
2570
2571          error('An update to %s inside a test was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + '  /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentName(fiber.type));
2572