Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.new.js
Source:ReactFiberWorkLoop.new.js
...525 // Check if we're not already rendering526 (executionContext & (RenderContext | CommitContext)) === NoContext527 ) {528 // Register pending interactions on the root to avoid losing traced interaction data.529 schedulePendingInteractions(root, lane);530 // This is a legacy edge case. The initial mount of a ReactDOM.render-ed531 // root inside of batchedUpdates should be synchronous, but layout updates532 // should be deferred until the end of the batch.533 performSyncWorkOnRoot(root);534 } else {535 ensureRootIsScheduled(root, eventTime);536 schedulePendingInteractions(root, lane);537 if (executionContext === NoContext) {538 // Flush the synchronous work now, unless we're already working or inside539 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of540 // scheduleCallbackForFiber to preserve the ability to schedule a callback541 // without immediately flushing it. We only do this for user-initiated542 // updates, to preserve historical behavior of legacy mode.543 resetRenderTimer();544 flushSyncCallbackQueue();545 }546 }547 } else {548 // Schedule a discrete update but only if it's not Sync.549 if (550 (executionContext & DiscreteEventContext) !== NoContext &&551 // Only updates at user-blocking priority or greater are considered552 // discrete, even inside a discrete event.553 (priorityLevel === UserBlockingSchedulerPriority ||554 priorityLevel === ImmediateSchedulerPriority)555 ) {556 // This is the result of a discrete event. Track the lowest priority557 // discrete update per root so we can flush them early, if needed.558 if (rootsWithPendingDiscreteUpdates === null) {559 rootsWithPendingDiscreteUpdates = new Set([root]);560 } else {561 rootsWithPendingDiscreteUpdates.add(root);562 }563 }564 // Schedule other updates after in case the callback is sync.565 ensureRootIsScheduled(root, eventTime);566 schedulePendingInteractions(root, lane);567 }568 // We use this when assigning a lane for a transition inside569 // `requestUpdateLane`. We assume it's the same as the root being updated,570 // since in the common case of a single root app it probably is. If it's not571 // the same root, then it's not a huge deal, we just might batch more stuff572 // together more than necessary.573 mostRecentlyUpdatedRoot = root;574}575// This is split into a separate function so we can mark a fiber with pending576// work without treating it as a typical update that originates from an event;577// e.g. retrying a Suspense boundary isn't an update, but it does schedule work578// on a fiber.579function markUpdateLaneFromFiberToRoot(580 sourceFiber: Fiber,581 lane: Lane,582): FiberRoot | null {583 // Update the source fiber's lanes584 sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);585 let alternate = sourceFiber.alternate;586 if (alternate !== null) {587 alternate.lanes = mergeLanes(alternate.lanes, lane);588 }589 if (__DEV__) {590 if (591 alternate === null &&592 (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags593 ) {594 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);595 }596 }597 // Walk the parent path to the root and update the child expiration time.598 let node = sourceFiber;599 let parent = sourceFiber.return;600 while (parent !== null) {601 parent.childLanes = mergeLanes(parent.childLanes, lane);602 alternate = parent.alternate;603 if (alternate !== null) {604 alternate.childLanes = mergeLanes(alternate.childLanes, lane);605 } else {606 if (__DEV__) {607 if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {608 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);609 }610 }611 }612 node = parent;613 parent = parent.return;614 }615 if (node.tag === HostRoot) {616 const root: FiberRoot = node.stateNode;617 return root;618 } else {619 return null;620 }621}622// Use this function to schedule a task for a root. There's only one task per623// root; if a task was already scheduled, we'll check to make sure the priority624// of the existing task is the same as the priority of the next level that the625// root has work on. This function is called on every update, and right before626// exiting a task.627function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {628 const existingCallbackNode = root.callbackNode;629 // Check if any lanes are being starved by other work. If so, mark them as630 // expired so we know to work on those next.631 markStarvedLanesAsExpired(root, currentTime);632 // Determine the next lanes to work on, and their priority.633 const nextLanes = getNextLanes(634 root,635 root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,636 );637 // This returns the priority level computed during the `getNextLanes` call.638 const newCallbackPriority = returnNextLanesPriority();639 if (nextLanes === NoLanes) {640 // Special case: There's nothing to work on.641 if (existingCallbackNode !== null) {642 cancelCallback(existingCallbackNode);643 root.callbackNode = null;644 root.callbackPriority = NoLanePriority;645 }646 return;647 }648 // Check if there's an existing task. We may be able to reuse it.649 if (existingCallbackNode !== null) {650 const existingCallbackPriority = root.callbackPriority;651 if (existingCallbackPriority === newCallbackPriority) {652 // The priority hasn't changed. We can reuse the existing task. Exit.653 return;654 }655 // The priority changed. Cancel the existing callback. We'll schedule a new656 // one below.657 cancelCallback(existingCallbackNode);658 }659 // Schedule a new callback.660 let newCallbackNode;661 if (newCallbackPriority === SyncLanePriority) {662 // Special case: Sync React callbacks are scheduled on a special663 // internal queue664 newCallbackNode = scheduleSyncCallback(665 performSyncWorkOnRoot.bind(null, root),666 );667 } else if (newCallbackPriority === SyncBatchedLanePriority) {668 newCallbackNode = scheduleCallback(669 ImmediateSchedulerPriority,670 performSyncWorkOnRoot.bind(null, root),671 );672 } else {673 const schedulerPriorityLevel = lanePriorityToSchedulerPriority(674 newCallbackPriority,675 );676 newCallbackNode = scheduleCallback(677 schedulerPriorityLevel,678 performConcurrentWorkOnRoot.bind(null, root),679 );680 }681 root.callbackPriority = newCallbackPriority;682 root.callbackNode = newCallbackNode;683}684// This is the entry point for every concurrent task, i.e. anything that685// goes through Scheduler.686function performConcurrentWorkOnRoot(root) {687 // Since we know we're in a React event, we can clear the current688 // event time. The next update will compute a new event time.689 currentEventTime = NoTimestamp;690 currentEventWipLanes = NoLanes;691 currentEventPendingLanes = NoLanes;692 invariant(693 (executionContext & (RenderContext | CommitContext)) === NoContext,694 'Should not already be working.',695 );696 // Flush any pending passive effects before deciding which lanes to work on,697 // in case they schedule additional work.698 const originalCallbackNode = root.callbackNode;699 const didFlushPassiveEffects = flushPassiveEffects();700 if (didFlushPassiveEffects) {701 // Something in the passive effect phase may have canceled the current task.702 // Check if the task node for this root was changed.703 if (root.callbackNode !== originalCallbackNode) {704 // The current task was canceled. Exit. We don't need to call705 // `ensureRootIsScheduled` because the check above implies either that706 // there's a new task, or that there's no remaining work on this root.707 return null;708 } else {709 // Current task was not canceled. Continue.710 }711 }712 // Determine the next expiration time to work on, using the fields stored713 // on the root.714 let lanes = getNextLanes(715 root,716 root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,717 );718 if (lanes === NoLanes) {719 // Defensive coding. This is never expected to happen.720 return null;721 }722 let exitStatus = renderRootConcurrent(root, lanes);723 if (724 includesSomeLane(725 workInProgressRootIncludedLanes,726 workInProgressRootUpdatedLanes,727 )728 ) {729 // The render included lanes that were updated during the render phase.730 // For example, when unhiding a hidden tree, we include all the lanes731 // that were previously skipped when the tree was hidden. That set of732 // lanes is a superset of the lanes we started rendering with.733 //734 // So we'll throw out the current work and restart.735 prepareFreshStack(root, NoLanes);736 } else if (exitStatus !== RootIncomplete) {737 if (exitStatus === RootErrored) {738 executionContext |= RetryAfterError;739 // If an error occurred during hydration,740 // discard server response and fall back to client side render.741 if (root.hydrate) {742 root.hydrate = false;743 clearContainer(root.containerInfo);744 }745 // If something threw an error, try rendering one more time. We'll render746 // synchronously to block concurrent data mutations, and we'll includes747 // all pending updates are included. If it still fails after the second748 // attempt, we'll give up and commit the resulting tree.749 lanes = getLanesToRetrySynchronouslyOnError(root);750 if (lanes !== NoLanes) {751 exitStatus = renderRootSync(root, lanes);752 }753 }754 if (exitStatus === RootFatalErrored) {755 const fatalError = workInProgressRootFatalError;756 prepareFreshStack(root, NoLanes);757 markRootSuspended(root, lanes);758 ensureRootIsScheduled(root, now());759 throw fatalError;760 }761 // We now have a consistent tree. The next step is either to commit it,762 // or, if something suspended, wait to commit it after a timeout.763 const finishedWork: Fiber = (root.current.alternate: any);764 root.finishedWork = finishedWork;765 root.finishedLanes = lanes;766 finishConcurrentRender(root, exitStatus, lanes);767 }768 ensureRootIsScheduled(root, now());769 if (root.callbackNode === originalCallbackNode) {770 // The task node scheduled for this root is the same one that's771 // currently executed. Need to return a continuation.772 return performConcurrentWorkOnRoot.bind(null, root);773 }774 return null;775}776function finishConcurrentRender(root, exitStatus, lanes) {777 switch (exitStatus) {778 case RootIncomplete:779 case RootFatalErrored: {780 invariant(false, 'Root did not complete. This is a bug in React.');781 }782 // Flow knows about invariant, so it complains if I add a break783 // statement, but eslint doesn't know about invariant, so it complains784 // if I do. eslint-disable-next-line no-fallthrough785 case RootErrored: {786 // We should have already attempted to retry this tree. If we reached787 // this point, it errored again. Commit it.788 commitRoot(root);789 break;790 }791 case RootSuspended: {792 markRootSuspended(root, lanes);793 // We have an acceptable loading state. We need to figure out if we794 // should immediately commit it or wait a bit.795 if (796 includesOnlyRetries(lanes) &&797 // do not delay if we're inside an act() scope798 !shouldForceFlushFallbacksInDEV()799 ) {800 // This render only included retries, no updates. Throttle committing801 // retries so that we don't show too many loading states too quickly.802 const msUntilTimeout =803 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();804 // Don't bother with a very short suspense time.805 if (msUntilTimeout > 10) {806 const nextLanes = getNextLanes(root, NoLanes);807 if (nextLanes !== NoLanes) {808 // There's additional work on this root.809 break;810 }811 const suspendedLanes = root.suspendedLanes;812 if (!isSubsetOfLanes(suspendedLanes, lanes)) {813 // We should prefer to render the fallback of at the last814 // suspended level. Ping the last suspended level to try815 // rendering it again.816 // FIXME: What if the suspended lanes are Idle? Should not restart.817 const eventTime = requestEventTime();818 markRootPinged(root, suspendedLanes, eventTime);819 break;820 }821 // The render is suspended, it hasn't timed out, and there's no822 // lower priority work to do. Instead of committing the fallback823 // immediately, wait for more data to arrive.824 root.timeoutHandle = scheduleTimeout(825 commitRoot.bind(null, root),826 msUntilTimeout,827 );828 break;829 }830 }831 // The work expired. Commit immediately.832 commitRoot(root);833 break;834 }835 case RootSuspendedWithDelay: {836 markRootSuspended(root, lanes);837 if (includesOnlyTransitions(lanes)) {838 // This is a transition, so we should exit without committing a839 // placeholder and without scheduling a timeout. Delay indefinitely840 // until we receive more data.841 break;842 }843 if (!shouldForceFlushFallbacksInDEV()) {844 // This is not a transition, but we did trigger an avoided state.845 // Schedule a placeholder to display after a short delay, using the Just846 // Noticeable Difference.847 // TODO: Is the JND optimization worth the added complexity? If this is848 // the only reason we track the event time, then probably not.849 // Consider removing.850 const mostRecentEventTime = getMostRecentEventTime(root, lanes);851 const eventTimeMs = mostRecentEventTime;852 const timeElapsedMs = now() - eventTimeMs;853 const msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs;854 // Don't bother with a very short suspense time.855 if (msUntilTimeout > 10) {856 // Instead of committing the fallback immediately, wait for more data857 // to arrive.858 root.timeoutHandle = scheduleTimeout(859 commitRoot.bind(null, root),860 msUntilTimeout,861 );862 break;863 }864 }865 // Commit the placeholder.866 commitRoot(root);867 break;868 }869 case RootCompleted: {870 // The work completed. Ready to commit.871 commitRoot(root);872 break;873 }874 default: {875 invariant(false, 'Unknown root exit status.');876 }877 }878}879function markRootSuspended(root, suspendedLanes) {880 // When suspending, we should always exclude lanes that were pinged or (more881 // rarely, since we try to avoid it) updated during the render phase.882 // TODO: Lol maybe there's a better way to factor this besides this883 // obnoxiously named function :)884 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);885 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);886 markRootSuspended_dontCallThisOneDirectly(root, suspendedLanes);887}888// This is the entry point for synchronous tasks that don't go889// through Scheduler890function performSyncWorkOnRoot(root) {891 invariant(892 (executionContext & (RenderContext | CommitContext)) === NoContext,893 'Should not already be working.',894 );895 flushPassiveEffects();896 let lanes;897 let exitStatus;898 if (899 root === workInProgressRoot &&900 includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)901 ) {902 // There's a partial tree, and at least one of its lanes has expired. Finish903 // rendering it before rendering the rest of the expired work.904 lanes = workInProgressRootRenderLanes;905 exitStatus = renderRootSync(root, lanes);906 if (907 includesSomeLane(908 workInProgressRootIncludedLanes,909 workInProgressRootUpdatedLanes,910 )911 ) {912 // The render included lanes that were updated during the render phase.913 // For example, when unhiding a hidden tree, we include all the lanes914 // that were previously skipped when the tree was hidden. That set of915 // lanes is a superset of the lanes we started rendering with.916 //917 // Note that this only happens when part of the tree is rendered918 // concurrently. If the whole tree is rendered synchronously, then there919 // are no interleaved events.920 lanes = getNextLanes(root, lanes);921 exitStatus = renderRootSync(root, lanes);922 }923 } else {924 lanes = getNextLanes(root, NoLanes);925 exitStatus = renderRootSync(root, lanes);926 }927 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {928 executionContext |= RetryAfterError;929 // If an error occurred during hydration,930 // discard server response and fall back to client side render.931 if (root.hydrate) {932 root.hydrate = false;933 clearContainer(root.containerInfo);934 }935 // If something threw an error, try rendering one more time. We'll render936 // synchronously to block concurrent data mutations, and we'll includes937 // all pending updates are included. If it still fails after the second938 // attempt, we'll give up and commit the resulting tree.939 lanes = getLanesToRetrySynchronouslyOnError(root);940 if (lanes !== NoLanes) {941 exitStatus = renderRootSync(root, lanes);942 }943 }944 if (exitStatus === RootFatalErrored) {945 const fatalError = workInProgressRootFatalError;946 prepareFreshStack(root, NoLanes);947 markRootSuspended(root, lanes);948 ensureRootIsScheduled(root, now());949 throw fatalError;950 }951 // We now have a consistent tree. Because this is a sync render, we952 // will commit it even if something suspended.953 const finishedWork: Fiber = (root.current.alternate: any);954 root.finishedWork = finishedWork;955 root.finishedLanes = lanes;956 commitRoot(root);957 // Before exiting, make sure there's a callback scheduled for the next958 // pending level.959 ensureRootIsScheduled(root, now());960 return null;961}962export function flushRoot(root: FiberRoot, lanes: Lanes) {963 markRootExpired(root, lanes);964 ensureRootIsScheduled(root, now());965 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {966 resetRenderTimer();967 flushSyncCallbackQueue();968 }969}970export function getExecutionContext(): ExecutionContext {971 return executionContext;972}973export function flushDiscreteUpdates() {974 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.975 // However, `act` uses `batchedUpdates`, so there's no way to distinguish976 // those two cases. Need to fix this before exposing flushDiscreteUpdates977 // as a public API.978 if (979 (executionContext & (BatchedContext | RenderContext | CommitContext)) !==980 NoContext981 ) {982 if (__DEV__) {983 if ((executionContext & RenderContext) !== NoContext) {984 console.error(985 'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +986 'already rendering.',987 );988 }989 }990 // We're already rendering, so we can't synchronously flush pending work.991 // This is probably a nested event dispatch triggered by a lifecycle/effect,992 // like `el.focus()`. Exit.993 return;994 }995 flushPendingDiscreteUpdates();996 // If the discrete updates scheduled passive effects, flush them now so that997 // they fire before the next serial event.998 flushPassiveEffects();999}1000export function deferredUpdates<A>(fn: () => A): A {1001 if (decoupleUpdatePriorityFromScheduler) {1002 const previousLanePriority = getCurrentUpdateLanePriority();1003 try {1004 setCurrentUpdateLanePriority(DefaultLanePriority);1005 return runWithPriority(NormalSchedulerPriority, fn);1006 } finally {1007 setCurrentUpdateLanePriority(previousLanePriority);1008 }1009 } else {1010 return runWithPriority(NormalSchedulerPriority, fn);1011 }1012}1013function flushPendingDiscreteUpdates() {1014 if (rootsWithPendingDiscreteUpdates !== null) {1015 // For each root with pending discrete updates, schedule a callback to1016 // immediately flush them.1017 const roots = rootsWithPendingDiscreteUpdates;1018 rootsWithPendingDiscreteUpdates = null;1019 roots.forEach(root => {1020 markDiscreteUpdatesExpired(root);1021 ensureRootIsScheduled(root, now());1022 });1023 }1024 // Now flush the immediate queue.1025 flushSyncCallbackQueue();1026}1027export function batchedUpdates<A, R>(fn: A => R, a: A): R {1028 const prevExecutionContext = executionContext;1029 executionContext |= BatchedContext;1030 try {1031 return fn(a);1032 } finally {1033 executionContext = prevExecutionContext;1034 if (executionContext === NoContext) {1035 // Flush the immediate callbacks that were scheduled during this batch1036 resetRenderTimer();1037 flushSyncCallbackQueue();1038 }1039 }1040}1041export function batchedEventUpdates<A, R>(fn: A => R, a: A): R {1042 const prevExecutionContext = executionContext;1043 executionContext |= EventContext;1044 try {1045 return fn(a);1046 } finally {1047 executionContext = prevExecutionContext;1048 if (executionContext === NoContext) {1049 // Flush the immediate callbacks that were scheduled during this batch1050 resetRenderTimer();1051 flushSyncCallbackQueue();1052 }1053 }1054}1055export function discreteUpdates<A, B, C, D, R>(1056 fn: (A, B, C) => R,1057 a: A,1058 b: B,1059 c: C,1060 d: D,1061): R {1062 const prevExecutionContext = executionContext;1063 executionContext |= DiscreteEventContext;1064 if (decoupleUpdatePriorityFromScheduler) {1065 const previousLanePriority = getCurrentUpdateLanePriority();1066 try {1067 setCurrentUpdateLanePriority(InputDiscreteLanePriority);1068 return runWithPriority(1069 UserBlockingSchedulerPriority,1070 fn.bind(null, a, b, c, d),1071 );1072 } finally {1073 setCurrentUpdateLanePriority(previousLanePriority);1074 executionContext = prevExecutionContext;1075 if (executionContext === NoContext) {1076 // Flush the immediate callbacks that were scheduled during this batch1077 resetRenderTimer();1078 flushSyncCallbackQueue();1079 }1080 }1081 } else {1082 try {1083 return runWithPriority(1084 UserBlockingSchedulerPriority,1085 fn.bind(null, a, b, c, d),1086 );1087 } finally {1088 executionContext = prevExecutionContext;1089 if (executionContext === NoContext) {1090 // Flush the immediate callbacks that were scheduled during this batch1091 resetRenderTimer();1092 flushSyncCallbackQueue();1093 }1094 }1095 }1096}1097export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {1098 const prevExecutionContext = executionContext;1099 executionContext &= ~BatchedContext;1100 executionContext |= LegacyUnbatchedContext;1101 try {1102 return fn(a);1103 } finally {1104 executionContext = prevExecutionContext;1105 if (executionContext === NoContext) {1106 // Flush the immediate callbacks that were scheduled during this batch1107 resetRenderTimer();1108 flushSyncCallbackQueue();1109 }1110 }1111}1112export function flushSync<A, R>(fn: A => R, a: A): R {1113 const prevExecutionContext = executionContext;1114 if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {1115 if (__DEV__) {1116 console.error(1117 'flushSync was called from inside a lifecycle method. React cannot ' +1118 'flush when React is already rendering. Consider moving this call to ' +1119 'a scheduler task or micro task.',1120 );1121 }1122 return fn(a);1123 }1124 executionContext |= BatchedContext;1125 if (decoupleUpdatePriorityFromScheduler) {1126 const previousLanePriority = getCurrentUpdateLanePriority();1127 try {1128 setCurrentUpdateLanePriority(SyncLanePriority);1129 if (fn) {1130 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));1131 } else {1132 return (undefined: $FlowFixMe);1133 }1134 } finally {1135 setCurrentUpdateLanePriority(previousLanePriority);1136 executionContext = prevExecutionContext;1137 // Flush the immediate callbacks that were scheduled during this batch.1138 // Note that this will happen even if batchedUpdates is higher up1139 // the stack.1140 flushSyncCallbackQueue();1141 }1142 } else {1143 try {1144 if (fn) {1145 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));1146 } else {1147 return (undefined: $FlowFixMe);1148 }1149 } finally {1150 executionContext = prevExecutionContext;1151 // Flush the immediate callbacks that were scheduled during this batch.1152 // Note that this will happen even if batchedUpdates is higher up1153 // the stack.1154 flushSyncCallbackQueue();1155 }1156 }1157}1158export function flushControlled(fn: () => mixed): void {1159 const prevExecutionContext = executionContext;1160 executionContext |= BatchedContext;1161 if (decoupleUpdatePriorityFromScheduler) {1162 const previousLanePriority = getCurrentUpdateLanePriority();1163 try {1164 setCurrentUpdateLanePriority(SyncLanePriority);1165 runWithPriority(ImmediateSchedulerPriority, fn);1166 } finally {1167 setCurrentUpdateLanePriority(previousLanePriority);1168 executionContext = prevExecutionContext;1169 if (executionContext === NoContext) {1170 // Flush the immediate callbacks that were scheduled during this batch1171 resetRenderTimer();1172 flushSyncCallbackQueue();1173 }1174 }1175 } else {1176 try {1177 runWithPriority(ImmediateSchedulerPriority, fn);1178 } finally {1179 executionContext = prevExecutionContext;1180 if (executionContext === NoContext) {1181 // Flush the immediate callbacks that were scheduled during this batch1182 resetRenderTimer();1183 flushSyncCallbackQueue();1184 }1185 }1186 }1187}1188export function pushRenderLanes(fiber: Fiber, lanes: Lanes) {1189 pushToStack(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);1190 subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);1191 workInProgressRootIncludedLanes = mergeLanes(1192 workInProgressRootIncludedLanes,1193 lanes,1194 );1195}1196export function popRenderLanes(fiber: Fiber) {1197 subtreeRenderLanes = subtreeRenderLanesCursor.current;1198 popFromStack(subtreeRenderLanesCursor, fiber);1199}1200function prepareFreshStack(root: FiberRoot, lanes: Lanes) {1201 root.finishedWork = null;1202 root.finishedLanes = NoLanes;1203 const timeoutHandle = root.timeoutHandle;1204 if (timeoutHandle !== noTimeout) {1205 // The root previous suspended and scheduled a timeout to commit a fallback1206 // state. Now that we have additional work, cancel the timeout.1207 root.timeoutHandle = noTimeout;1208 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above1209 cancelTimeout(timeoutHandle);1210 }1211 if (workInProgress !== null) {1212 let interruptedWork = workInProgress.return;1213 while (interruptedWork !== null) {1214 unwindInterruptedWork(interruptedWork);1215 interruptedWork = interruptedWork.return;1216 }1217 }1218 workInProgressRoot = root;1219 workInProgress = createWorkInProgress(root.current, null);1220 workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;1221 workInProgressRootExitStatus = RootIncomplete;1222 workInProgressRootFatalError = null;1223 workInProgressRootSkippedLanes = NoLanes;1224 workInProgressRootUpdatedLanes = NoLanes;1225 workInProgressRootPingedLanes = NoLanes;1226 if (enableSchedulerTracing) {1227 spawnedWorkDuringRender = null;1228 }1229 if (__DEV__) {1230 ReactStrictModeWarnings.discardPendingWarnings();1231 }1232}1233function handleError(root, thrownValue): void {1234 do {1235 let erroredWork = workInProgress;1236 try {1237 // Reset module-level state that was set during the render phase.1238 resetContextDependencies();1239 resetHooksAfterThrow();1240 resetCurrentDebugFiberInDEV();1241 // TODO: I found and added this missing line while investigating a1242 // separate issue. Write a regression test using string refs.1243 ReactCurrentOwner.current = null;1244 if (erroredWork === null || erroredWork.return === null) {1245 // Expected to be working on a non-root fiber. This is a fatal error1246 // because there's no ancestor that can handle it; the root is1247 // supposed to capture all errors that weren't caught by an error1248 // boundary.1249 workInProgressRootExitStatus = RootFatalErrored;1250 workInProgressRootFatalError = thrownValue;1251 // Set `workInProgress` to null. This represents advancing to the next1252 // sibling, or the parent if there are no siblings. But since the root1253 // has no siblings nor a parent, we set it to null. Usually this is1254 // handled by `completeUnitOfWork` or `unwindWork`, but since we're1255 // intentionally not calling those, we need set it here.1256 // TODO: Consider calling `unwindWork` to pop the contexts.1257 workInProgress = null;1258 return;1259 }1260 if (enableProfilerTimer && erroredWork.mode & ProfileMode) {1261 // Record the time spent rendering before an error was thrown. This1262 // avoids inaccurate Profiler durations in the case of a1263 // suspended render.1264 stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);1265 }1266 throwException(1267 root,1268 erroredWork.return,1269 erroredWork,1270 thrownValue,1271 workInProgressRootRenderLanes,1272 );1273 completeUnitOfWork(erroredWork);1274 } catch (yetAnotherThrownValue) {1275 // Something in the return path also threw.1276 thrownValue = yetAnotherThrownValue;1277 if (workInProgress === erroredWork && erroredWork !== null) {1278 // If this boundary has already errored, then we had trouble processing1279 // the error. Bubble it to the next boundary.1280 erroredWork = erroredWork.return;1281 workInProgress = erroredWork;1282 } else {1283 erroredWork = workInProgress;1284 }1285 continue;1286 }1287 // Return to the normal work loop.1288 return;1289 } while (true);1290}1291function pushDispatcher() {1292 const prevDispatcher = ReactCurrentDispatcher.current;1293 ReactCurrentDispatcher.current = ContextOnlyDispatcher;1294 if (prevDispatcher === null) {1295 // The React isomorphic package does not include a default dispatcher.1296 // Instead the first renderer will lazily attach one, in order to give1297 // nicer error messages.1298 return ContextOnlyDispatcher;1299 } else {1300 return prevDispatcher;1301 }1302}1303function popDispatcher(prevDispatcher) {1304 ReactCurrentDispatcher.current = prevDispatcher;1305}1306function pushInteractions(root) {1307 if (enableSchedulerTracing) {1308 const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1309 __interactionsRef.current = root.memoizedInteractions;1310 return prevInteractions;1311 }1312 return null;1313}1314function popInteractions(prevInteractions) {1315 if (enableSchedulerTracing) {1316 __interactionsRef.current = prevInteractions;1317 }1318}1319export function markCommitTimeOfFallback() {1320 globalMostRecentFallbackTime = now();1321}1322export function markSkippedUpdateLanes(lane: Lane | Lanes): void {1323 workInProgressRootSkippedLanes = mergeLanes(1324 lane,1325 workInProgressRootSkippedLanes,1326 );1327}1328export function renderDidSuspend(): void {1329 if (workInProgressRootExitStatus === RootIncomplete) {1330 workInProgressRootExitStatus = RootSuspended;1331 }1332}1333export function renderDidSuspendDelayIfPossible(): void {1334 if (1335 workInProgressRootExitStatus === RootIncomplete ||1336 workInProgressRootExitStatus === RootSuspended1337 ) {1338 workInProgressRootExitStatus = RootSuspendedWithDelay;1339 }1340 // Check if there are updates that we skipped tree that might have unblocked1341 // this render.1342 if (1343 workInProgressRoot !== null &&1344 (includesNonIdleWork(workInProgressRootSkippedLanes) ||1345 includesNonIdleWork(workInProgressRootUpdatedLanes))1346 ) {1347 // Mark the current render as suspended so that we switch to working on1348 // the updates that were skipped. Usually we only suspend at the end of1349 // the render phase.1350 // TODO: We should probably always mark the root as suspended immediately1351 // (inside this function), since by suspending at the end of the render1352 // phase introduces a potential mistake where we suspend lanes that were1353 // pinged or updated while we were rendering.1354 markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes);1355 }1356}1357export function renderDidError() {1358 if (workInProgressRootExitStatus !== RootCompleted) {1359 workInProgressRootExitStatus = RootErrored;1360 }1361}1362// Called during render to determine if anything has suspended.1363// Returns false if we're not sure.1364export function renderHasNotSuspendedYet(): boolean {1365 // If something errored or completed, we can't really be sure,1366 // so those are false.1367 return workInProgressRootExitStatus === RootIncomplete;1368}1369function renderRootSync(root: FiberRoot, lanes: Lanes) {1370 const prevExecutionContext = executionContext;1371 executionContext |= RenderContext;1372 const prevDispatcher = pushDispatcher();1373 // If the root or lanes have changed, throw out the existing stack1374 // and prepare a fresh one. Otherwise we'll continue where we left off.1375 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1376 prepareFreshStack(root, lanes);1377 startWorkOnPendingInteractions(root, lanes);1378 }1379 const prevInteractions = pushInteractions(root);1380 if (__DEV__) {1381 if (enableDebugTracing) {1382 logRenderStarted(lanes);1383 }1384 }1385 if (enableSchedulingProfiler) {1386 markRenderStarted(lanes);1387 }1388 do {1389 try {1390 workLoopSync();1391 break;1392 } catch (thrownValue) {1393 handleError(root, thrownValue);1394 }1395 } while (true);1396 resetContextDependencies();1397 if (enableSchedulerTracing) {1398 popInteractions(((prevInteractions: any): Set<Interaction>));1399 }1400 executionContext = prevExecutionContext;1401 popDispatcher(prevDispatcher);1402 if (workInProgress !== null) {1403 // This is a sync render, so we should have finished the whole tree.1404 invariant(1405 false,1406 'Cannot commit an incomplete root. This error is likely caused by a ' +1407 'bug in React. Please file an issue.',1408 );1409 }1410 if (__DEV__) {1411 if (enableDebugTracing) {1412 logRenderStopped();1413 }1414 }1415 if (enableSchedulingProfiler) {1416 markRenderStopped();1417 }1418 // Set this to null to indicate there's no in-progress render.1419 workInProgressRoot = null;1420 workInProgressRootRenderLanes = NoLanes;1421 return workInProgressRootExitStatus;1422}1423// The work loop is an extremely hot path. Tell Closure not to inline it.1424/** @noinline */1425function workLoopSync() {1426 // Already timed out, so perform work without checking if we need to yield.1427 while (workInProgress !== null) {1428 performUnitOfWork(workInProgress);1429 }1430}1431function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {1432 const prevExecutionContext = executionContext;1433 executionContext |= RenderContext;1434 const prevDispatcher = pushDispatcher();1435 // If the root or lanes have changed, throw out the existing stack1436 // and prepare a fresh one. Otherwise we'll continue where we left off.1437 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1438 resetRenderTimer();1439 prepareFreshStack(root, lanes);1440 startWorkOnPendingInteractions(root, lanes);1441 }1442 const prevInteractions = pushInteractions(root);1443 if (__DEV__) {1444 if (enableDebugTracing) {1445 logRenderStarted(lanes);1446 }1447 }1448 if (enableSchedulingProfiler) {1449 markRenderStarted(lanes);1450 }1451 do {1452 try {1453 workLoopConcurrent();1454 break;1455 } catch (thrownValue) {1456 handleError(root, thrownValue);1457 }1458 } while (true);1459 resetContextDependencies();1460 if (enableSchedulerTracing) {1461 popInteractions(((prevInteractions: any): Set<Interaction>));1462 }1463 popDispatcher(prevDispatcher);1464 executionContext = prevExecutionContext;1465 if (__DEV__) {1466 if (enableDebugTracing) {1467 logRenderStopped();1468 }1469 }1470 // Check if the tree has completed.1471 if (workInProgress !== null) {1472 // Still work remaining.1473 if (enableSchedulingProfiler) {1474 markRenderYielded();1475 }1476 return RootIncomplete;1477 } else {1478 // Completed the tree.1479 if (enableSchedulingProfiler) {1480 markRenderStopped();1481 }1482 // Set this to null to indicate there's no in-progress render.1483 workInProgressRoot = null;1484 workInProgressRootRenderLanes = NoLanes;1485 // Return the final exit status.1486 return workInProgressRootExitStatus;1487 }1488}1489/** @noinline */1490function workLoopConcurrent() {1491 // Perform work until Scheduler asks us to yield1492 while (workInProgress !== null && !shouldYield()) {1493 performUnitOfWork(workInProgress);1494 }1495}1496function performUnitOfWork(unitOfWork: Fiber): void {1497 // The current, flushed, state of this fiber is the alternate. Ideally1498 // nothing should rely on this, but relying on it here means that we don't1499 // need an additional field on the work in progress.1500 const current = unitOfWork.alternate;1501 setCurrentDebugFiberInDEV(unitOfWork);1502 let next;1503 if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {1504 startProfilerTimer(unitOfWork);1505 next = beginWork(current, unitOfWork, subtreeRenderLanes);1506 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);1507 } else {1508 next = beginWork(current, unitOfWork, subtreeRenderLanes);1509 }1510 resetCurrentDebugFiberInDEV();1511 unitOfWork.memoizedProps = unitOfWork.pendingProps;1512 if (next === null) {1513 // If this doesn't spawn new work, complete the current work.1514 completeUnitOfWork(unitOfWork);1515 } else {1516 workInProgress = next;1517 }1518 ReactCurrentOwner.current = null;1519}1520function completeUnitOfWork(unitOfWork: Fiber): void {1521 // Attempt to complete the current unit of work, then move to the next1522 // sibling. If there are no more siblings, return to the parent fiber.1523 let completedWork = unitOfWork;1524 do {1525 // The current, flushed, state of this fiber is the alternate. Ideally1526 // nothing should rely on this, but relying on it here means that we don't1527 // need an additional field on the work in progress.1528 const current = completedWork.alternate;1529 const returnFiber = completedWork.return;1530 // Check if the work completed or if something threw.1531 if ((completedWork.flags & Incomplete) === NoFlags) {1532 setCurrentDebugFiberInDEV(completedWork);1533 let next;1534 if (1535 !enableProfilerTimer ||1536 (completedWork.mode & ProfileMode) === NoMode1537 ) {1538 next = completeWork(current, completedWork, subtreeRenderLanes);1539 } else {1540 startProfilerTimer(completedWork);1541 next = completeWork(current, completedWork, subtreeRenderLanes);1542 // Update render duration assuming we didn't error.1543 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1544 }1545 resetCurrentDebugFiberInDEV();1546 if (next !== null) {1547 // Completing this fiber spawned new work. Work on that next.1548 workInProgress = next;1549 return;1550 }1551 } else {1552 // This fiber did not complete because something threw. Pop values off1553 // the stack without entering the complete phase. If this is a boundary,1554 // capture values if possible.1555 const next = unwindWork(completedWork, subtreeRenderLanes);1556 // Because this fiber did not complete, don't reset its expiration time.1557 if (next !== null) {1558 // If completing this work spawned new work, do that next. We'll come1559 // back here again.1560 // Since we're restarting, remove anything that is not a host effect1561 // from the effect tag.1562 next.flags &= HostEffectMask;1563 workInProgress = next;1564 return;1565 }1566 if (1567 enableProfilerTimer &&1568 (completedWork.mode & ProfileMode) !== NoMode1569 ) {1570 // Record the render duration for the fiber that errored.1571 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1572 // Include the time spent working on failed children before continuing.1573 let actualDuration = completedWork.actualDuration;1574 let child = completedWork.child;1575 while (child !== null) {1576 actualDuration += child.actualDuration;1577 child = child.sibling;1578 }1579 completedWork.actualDuration = actualDuration;1580 }1581 if (returnFiber !== null) {1582 // Mark the parent fiber as incomplete1583 returnFiber.flags |= Incomplete;1584 returnFiber.subtreeFlags = NoFlags;1585 returnFiber.deletions = null;1586 }1587 }1588 const siblingFiber = completedWork.sibling;1589 if (siblingFiber !== null) {1590 // If there is more work to do in this returnFiber, do that next.1591 workInProgress = siblingFiber;1592 return;1593 }1594 // Otherwise, return to the parent1595 completedWork = returnFiber;1596 // Update the next thing we're working on in case something throws.1597 workInProgress = completedWork;1598 } while (completedWork !== null);1599 // We've reached the root.1600 if (workInProgressRootExitStatus === RootIncomplete) {1601 workInProgressRootExitStatus = RootCompleted;1602 }1603}1604function commitRoot(root) {1605 const renderPriorityLevel = getCurrentPriorityLevel();1606 runWithPriority(1607 ImmediateSchedulerPriority,1608 commitRootImpl.bind(null, root, renderPriorityLevel),1609 );1610 return null;1611}1612function commitRootImpl(root, renderPriorityLevel) {1613 do {1614 // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1615 // means `flushPassiveEffects` will sometimes result in additional1616 // passive effects. So we need to keep flushing in a loop until there are1617 // no more pending effects.1618 // TODO: Might be better if `flushPassiveEffects` did not automatically1619 // flush synchronous work at the end, to avoid factoring hazards like this.1620 flushPassiveEffects();1621 } while (rootWithPendingPassiveEffects !== null);1622 flushRenderPhaseStrictModeWarningsInDEV();1623 invariant(1624 (executionContext & (RenderContext | CommitContext)) === NoContext,1625 'Should not already be working.',1626 );1627 const finishedWork = root.finishedWork;1628 const lanes = root.finishedLanes;1629 if (__DEV__) {1630 if (enableDebugTracing) {1631 logCommitStarted(lanes);1632 }1633 }1634 if (enableSchedulingProfiler) {1635 markCommitStarted(lanes);1636 }1637 // 没æéè¦æ´æ°çFiberèç¹1638 if (finishedWork === null) {1639 if (__DEV__) {1640 if (enableDebugTracing) {1641 logCommitStopped();1642 }1643 }1644 if (enableSchedulingProfiler) {1645 markCommitStopped();1646 }1647 return null;1648 }1649 root.finishedWork = null;1650 root.finishedLanes = NoLanes;1651 invariant(1652 finishedWork !== root.current,1653 'Cannot commit the same tree as before. This error is likely caused by ' +1654 'a bug in React. Please file an issue.',1655 );1656 // commitRoot never returns a continuation; it always finishes synchronously.1657 // So we can clear these now to allow a new callback to be scheduled.1658 root.callbackNode = null;1659 // Update the first and last pending times on this root. The new first1660 // pending time is whatever is left on the root fiber.1661 // å并ææçéé1662 let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);1663 markRootFinished(root, remainingLanes);1664 // Clear already finished discrete updates in case that a later call of1665 // `flushDiscreteUpdates` starts a useless render pass which may cancels1666 // a scheduled timeout.1667 if (rootsWithPendingDiscreteUpdates !== null) {1668 if (1669 !hasDiscreteLanes(remainingLanes) &&1670 rootsWithPendingDiscreteUpdates.has(root)1671 ) {1672 rootsWithPendingDiscreteUpdates.delete(root);1673 }1674 }1675 // 说ææ¬æ¬¡æ´æ°å·²ç»å®æäºï¼å°ä¸äºåééç½®1676 if (root === workInProgressRoot) {1677 // We can reset these now that they are finished.1678 workInProgressRoot = null;1679 workInProgress = null;1680 workInProgressRootRenderLanes = NoLanes;1681 } else {1682 // This indicates that the last root we worked on is not the same one that1683 // we're committing now. This most commonly happens when a suspended root1684 // times out.1685 }1686 // Check if there are any effects in the whole tree.1687 // TODO: This is left over from the effect list implementation, where we had1688 // to check for the existence of `firstEffect` to satsify Flow. I think the1689 // only other reason this optimization exists is because it affects profiling.1690 // Reconsider whether this is necessary.1691 const subtreeHasEffects =1692 (finishedWork.subtreeFlags &1693 (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==1694 NoFlags;1695 const rootHasEffect =1696 (finishedWork.flags &1697 (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==1698 NoFlags;1699 // æéè¦å¤ççå¯ä½ç¨1700 if (subtreeHasEffects || rootHasEffect) {1701 let previousLanePriority;1702 if (decoupleUpdatePriorityFromScheduler) {1703 previousLanePriority = getCurrentUpdateLanePriority();1704 setCurrentUpdateLanePriority(SyncLanePriority);1705 }1706 // 设置æ§è¡ä¸ä¸æ1707 const prevExecutionContext = executionContext;1708 executionContext |= CommitContext;1709 const prevInteractions = pushInteractions(root);1710 // Reset this to null before calling lifecycles1711 ReactCurrentOwner.current = null;1712 // The commit phase is broken into several sub-phases. We do a separate pass1713 // of the effect list for each phase: all mutation effects come before all1714 // layout effects, and so on.1715 // The first phase a "before mutation" phase. We use this phase to read the1716 // state of the host tree right before we mutate it. This is where1717 // getSnapshotBeforeUpdate is called.1718 focusedInstanceHandle = prepareForCommit(root.containerInfo);1719 shouldFireAfterActiveInstanceBlur = false;1720 commitBeforeMutationEffects(finishedWork);1721 // We no longer need to track the active instance fiber1722 focusedInstanceHandle = null;1723 if (enableProfilerTimer) {1724 // Mark the current commit time to be shared by all Profilers in this1725 // batch. This enables them to be grouped later.1726 recordCommitTime();1727 }1728 // æDOMå
ç´ æ¸²æå°é¡µé¢ä¸1729 // The next phase is the mutation phase, where we mutate the host tree.1730 commitMutationEffects(finishedWork, root, renderPriorityLevel);1731 if (shouldFireAfterActiveInstanceBlur) {1732 afterActiveInstanceBlur();1733 }1734 resetAfterCommit(root.containerInfo);1735 // The work-in-progress tree is now the current tree. This must come after1736 // the mutation phase, so that the previous tree is still current during1737 // componentWillUnmount, but before the layout phase, so that the finished1738 // work is current during componentDidMount/Update.1739 // å¨æ¤ä¹åï¼root.current æåäºwork-in-progress tree1740 root.current = finishedWork;1741 // The next phase is the layout phase, where we call effects that read1742 // the host tree after it's been mutated. The idiomatic use case for this is1743 // layout, but class component lifecycles also fire here for legacy reasons.1744 if (__DEV__) {1745 if (enableDebugTracing) {1746 logLayoutEffectsStarted(lanes);1747 }1748 }1749 if (enableSchedulingProfiler) {1750 markLayoutEffectsStarted(lanes);1751 }1752 if (__DEV__) {1753 setCurrentDebugFiberInDEV(finishedWork);1754 invokeGuardedCallback(1755 null,1756 recursivelyCommitLayoutEffects,1757 null,1758 finishedWork,1759 root,1760 );1761 if (hasCaughtError()) {1762 const error = clearCaughtError();1763 captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);1764 }1765 resetCurrentDebugFiberInDEV();1766 } else {1767 try {1768 recursivelyCommitLayoutEffects(finishedWork, root);1769 } catch (error) {1770 captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);1771 }1772 }1773 if (__DEV__) {1774 if (enableDebugTracing) {1775 logLayoutEffectsStopped();1776 }1777 }1778 if (enableSchedulingProfiler) {1779 markLayoutEffectsStopped();1780 }1781 // If there are pending passive effects, schedule a callback to process them.1782 if (1783 (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||1784 (finishedWork.flags & PassiveMask) !== NoFlags1785 ) {1786 if (!rootDoesHavePassiveEffects) {1787 rootDoesHavePassiveEffects = true;1788 scheduleCallback(NormalSchedulerPriority, () => {1789 flushPassiveEffects();1790 return null;1791 });1792 }1793 }1794 // Tell Scheduler to yield at the end of the frame, so the browser has an1795 // opportunity to paint.1796 requestPaint();1797 if (enableSchedulerTracing) {1798 popInteractions(((prevInteractions: any): Set<Interaction>));1799 }1800 executionContext = prevExecutionContext;1801 if (decoupleUpdatePriorityFromScheduler && previousLanePriority != null) {1802 // Reset the priority to the previous non-sync value.1803 setCurrentUpdateLanePriority(previousLanePriority);1804 }1805 } else {1806 // No effects.1807 root.current = finishedWork;1808 // Measure these anyway so the flamegraph explicitly shows that there were1809 // no effects.1810 // TODO: Maybe there's a better way to report this.1811 if (enableProfilerTimer) {1812 recordCommitTime();1813 }1814 }1815 const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1816 if (rootDoesHavePassiveEffects) {1817 // This commit has passive effects. Stash a reference to them. But don't1818 // schedule a callback until after flushing layout work.1819 rootDoesHavePassiveEffects = false;1820 rootWithPendingPassiveEffects = root;1821 pendingPassiveEffectsLanes = lanes;1822 pendingPassiveEffectsRenderPriority = renderPriorityLevel;1823 }1824 // Read this again, since an effect might have updated it1825 remainingLanes = root.pendingLanes;1826 // Check if there's remaining work on this root1827 if (remainingLanes !== NoLanes) {1828 if (enableSchedulerTracing) {1829 if (spawnedWorkDuringRender !== null) {1830 const expirationTimes = spawnedWorkDuringRender;1831 spawnedWorkDuringRender = null;1832 for (let i = 0; i < expirationTimes.length; i++) {1833 scheduleInteractions(1834 root,1835 expirationTimes[i],1836 root.memoizedInteractions,1837 );1838 }1839 }1840 schedulePendingInteractions(root, remainingLanes);1841 }1842 } else {1843 // If there's no remaining work, we can clear the set of already failed1844 // error boundaries.1845 legacyErrorBoundariesThatAlreadyFailed = null;1846 }1847 if (__DEV__ && enableDoubleInvokingEffects) {1848 if (!rootDidHavePassiveEffects) {1849 commitDoubleInvokeEffectsInDEV(root.current, false);1850 }1851 }1852 if (enableSchedulerTracing) {1853 if (!rootDidHavePassiveEffects) {1854 // If there are no passive effects, then we can complete the pending interactions.1855 // Otherwise, we'll wait until after the passive effects are flushed.1856 // Wait to do this until after remaining work has been scheduled,1857 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1858 finishPendingInteractions(root, lanes);1859 }1860 }1861 if (remainingLanes === SyncLane) {1862 // Count the number of times the root synchronously re-renders without1863 // finishing. If there are too many, it indicates an infinite update loop.1864 if (root === rootWithNestedUpdates) {1865 nestedUpdateCount++;1866 } else {1867 nestedUpdateCount = 0;1868 rootWithNestedUpdates = root;1869 }1870 } else {1871 nestedUpdateCount = 0;1872 }1873 onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);1874 if (__DEV__) {1875 onCommitRootTestSelector();1876 }1877 // Always call this before exiting `commitRoot`, to ensure that any1878 // additional work on this root is scheduled.1879 ensureRootIsScheduled(root, now());1880 if (hasUncaughtError) {1881 hasUncaughtError = false;1882 const error = firstUncaughtError;1883 firstUncaughtError = null;1884 throw error;1885 }1886 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1887 if (__DEV__) {1888 if (enableDebugTracing) {1889 logCommitStopped();1890 }1891 }1892 if (enableSchedulingProfiler) {1893 markCommitStopped();1894 }1895 // This is a legacy edge case. We just committed the initial mount of1896 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1897 // synchronously, but layout updates should be deferred until the end1898 // of the batch.1899 return null;1900 }1901 // If layout work was scheduled, flush it now.1902 flushSyncCallbackQueue();1903 if (__DEV__) {1904 if (enableDebugTracing) {1905 logCommitStopped();1906 }1907 }1908 if (enableSchedulingProfiler) {1909 markCommitStopped();1910 }1911 return null;1912}1913function commitBeforeMutationEffects(firstChild: Fiber) {1914 let fiber = firstChild;1915 while (fiber !== null) {1916 // å¤çéè¦å é¤çfiber autoFocusãblur é»è¾ã1917 if (fiber.deletions !== null) {1918 commitBeforeMutationEffectsDeletions(fiber.deletions);1919 }1920 // éå½è°ç¨å¤çåèç¹1921 if (fiber.child !== null) {1922 const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;1923 if (primarySubtreeFlags !== NoFlags) {1924 commitBeforeMutationEffects(fiber.child);1925 }1926 }1927 if (__DEV__) {1928 setCurrentDebugFiberInDEV(fiber);1929 invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);1930 if (hasCaughtError()) {1931 const error = clearCaughtError();1932 captureCommitPhaseError(fiber, fiber.return, error);1933 }1934 resetCurrentDebugFiberInDEV();1935 } else {1936 try {1937 // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1938 // å¼æ¥è°åº¦useEffect1939 commitBeforeMutationEffectsImpl(fiber);1940 } catch (error) {1941 captureCommitPhaseError(fiber, fiber.return, error);1942 }1943 }1944 // è¿åå
å¼èç¹ï¼æ¥ç循ç¯1945 fiber = fiber.sibling;1946 }1947}1948function commitBeforeMutationEffectsImpl(fiber: Fiber) {1949 const current = fiber.alternate;1950 const flags = fiber.flags;1951 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1952 // Check to see if the focused element was inside of a hidden (Suspense) subtree.1953 // TODO: Move this out of the hot path using a dedicated effect tag.1954 if (1955 fiber.tag === SuspenseComponent &&1956 isSuspenseBoundaryBeingHidden(current, fiber) &&1957 doesFiberContain(fiber, focusedInstanceHandle)1958 ) {1959 shouldFireAfterActiveInstanceBlur = true;1960 beforeActiveInstanceBlur();1961 }1962 }1963 if ((flags & Snapshot) !== NoFlags) {1964 setCurrentDebugFiberInDEV(fiber);1965 // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1966 commitBeforeMutationEffectOnFiber(current, fiber);1967 resetCurrentDebugFiberInDEV();1968 }1969 // è°åº¦useEffect1970 if ((flags & Passive) !== NoFlags) {1971 // If there are passive effects, schedule a callback to flush at1972 // the earliest opportunity.1973 if (!rootDoesHavePassiveEffects) {1974 rootDoesHavePassiveEffects = true;1975 scheduleCallback(NormalSchedulerPriority, () => {1976 flushPassiveEffects();1977 return null;1978 });1979 }1980 }1981}1982function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {1983 for (let i = 0; i < deletions.length; i++) {1984 const fiber = deletions[i];1985 // TODO (effects) It would be nice to avoid calling doesFiberContain()1986 // Maybe we can repurpose one of the subtreeFlags positions for this instead?1987 // Use it to store which part of the tree the focused instance is in?1988 // This assumes we can safely determine that instance during the "render" phase.1989 if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {1990 shouldFireAfterActiveInstanceBlur = true;1991 beforeActiveInstanceBlur();1992 }1993 }1994}1995function commitMutationEffects(1996 firstChild: Fiber,1997 root: FiberRoot,1998 renderPriorityLevel: ReactPriorityLevel,1999) {2000 let fiber = firstChild;2001 while (fiber !== null) {2002 const deletions = fiber.deletions;2003 if (deletions !== null) {2004 commitMutationEffectsDeletions(2005 deletions,2006 fiber,2007 root,2008 renderPriorityLevel,2009 );2010 }2011 if (fiber.child !== null) {2012 const mutationFlags = fiber.subtreeFlags & MutationMask;2013 if (mutationFlags !== NoFlags) {2014 commitMutationEffects(fiber.child, root, renderPriorityLevel);2015 }2016 }2017 if (__DEV__) {2018 setCurrentDebugFiberInDEV(fiber);2019 invokeGuardedCallback(2020 null,2021 commitMutationEffectsImpl,2022 null,2023 fiber,2024 root,2025 renderPriorityLevel,2026 );2027 if (hasCaughtError()) {2028 const error = clearCaughtError();2029 captureCommitPhaseError(fiber, fiber.return, error);2030 }2031 resetCurrentDebugFiberInDEV();2032 } else {2033 try {2034 commitMutationEffectsImpl(fiber, root, renderPriorityLevel);2035 } catch (error) {2036 captureCommitPhaseError(fiber, fiber.return, error);2037 }2038 }2039 fiber = fiber.sibling;2040 }2041}2042function commitMutationEffectsImpl(2043 fiber: Fiber,2044 root: FiberRoot,2045 renderPriorityLevel,2046) {2047 const flags = fiber.flags;2048 if (flags & ContentReset) {2049 commitResetTextContent(fiber);2050 }2051 if (flags & Ref) {2052 const current = fiber.alternate;2053 if (current !== null) {2054 commitDetachRef(current);2055 }2056 if (enableScopeAPI) {2057 // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.2058 if (fiber.tag === ScopeComponent) {2059 commitAttachRef(fiber);2060 }2061 }2062 }2063 // The following switch statement is only concerned about placement,2064 // updates, and deletions. To avoid needing to add a case for every possible2065 // bitmap value, we remove the secondary effects from the effect tag and2066 // switch on that value.2067 const primaryFlags = flags & (Placement | Update | Hydrating);2068 switch (primaryFlags) {2069 case Placement: {2070 commitPlacement(fiber);2071 // Clear the "placement" from effect tag so that we know that this is2072 // inserted, before any life-cycles like componentDidMount gets called.2073 // TODO: findDOMNode doesn't rely on this any more but isMounted does2074 // and isMounted is deprecated anyway so we should be able to kill this.2075 fiber.flags &= ~Placement;2076 break;2077 }2078 case PlacementAndUpdate: {2079 // Placement2080 commitPlacement(fiber);2081 // Clear the "placement" from effect tag so that we know that this is2082 // inserted, before any life-cycles like componentDidMount gets called.2083 fiber.flags &= ~Placement;2084 // Update2085 const current = fiber.alternate;2086 commitWork(current, fiber);2087 break;2088 }2089 case Hydrating: {2090 fiber.flags &= ~Hydrating;2091 break;2092 }2093 case HydratingAndUpdate: {2094 fiber.flags &= ~Hydrating;2095 // Update2096 const current = fiber.alternate;2097 commitWork(current, fiber);2098 break;2099 }2100 case Update: {2101 const current = fiber.alternate;2102 commitWork(current, fiber);2103 break;2104 }2105 }2106}2107function commitMutationEffectsDeletions(2108 deletions: Array<Fiber>,2109 nearestMountedAncestor: Fiber,2110 root: FiberRoot,2111 renderPriorityLevel,2112) {2113 for (let i = 0; i < deletions.length; i++) {2114 const childToDelete = deletions[i];2115 if (__DEV__) {2116 invokeGuardedCallback(2117 null,2118 commitDeletion,2119 null,2120 root,2121 childToDelete,2122 nearestMountedAncestor,2123 renderPriorityLevel,2124 );2125 if (hasCaughtError()) {2126 const error = clearCaughtError();2127 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2128 }2129 } else {2130 try {2131 commitDeletion(2132 root,2133 childToDelete,2134 nearestMountedAncestor,2135 renderPriorityLevel,2136 );2137 } catch (error) {2138 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2139 }2140 }2141 }2142}2143export function schedulePassiveEffectCallback() {2144 if (!rootDoesHavePassiveEffects) {2145 rootDoesHavePassiveEffects = true;2146 scheduleCallback(NormalSchedulerPriority, () => {2147 flushPassiveEffects();2148 return null;2149 });2150 }2151}2152export function flushPassiveEffects(): boolean {2153 // Returns whether passive effects were flushed.2154 if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {2155 const priorityLevel =2156 pendingPassiveEffectsRenderPriority > NormalSchedulerPriority2157 ? NormalSchedulerPriority2158 : pendingPassiveEffectsRenderPriority;2159 pendingPassiveEffectsRenderPriority = NoSchedulerPriority;2160 if (decoupleUpdatePriorityFromScheduler) {2161 const previousLanePriority = getCurrentUpdateLanePriority();2162 try {2163 setCurrentUpdateLanePriority(2164 schedulerPriorityToLanePriority(priorityLevel),2165 );2166 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2167 } finally {2168 setCurrentUpdateLanePriority(previousLanePriority);2169 }2170 } else {2171 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2172 }2173 }2174 return false;2175}2176function flushPassiveMountEffects(root, firstChild: Fiber): void {2177 let fiber = firstChild;2178 while (fiber !== null) {2179 let prevProfilerOnStack = null;2180 if (enableProfilerTimer && enableProfilerCommitHooks) {2181 if (fiber.tag === Profiler) {2182 prevProfilerOnStack = nearestProfilerOnStack;2183 nearestProfilerOnStack = fiber;2184 }2185 }2186 const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;2187 if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {2188 flushPassiveMountEffects(root, fiber.child);2189 }2190 if ((fiber.flags & Passive) !== NoFlags) {2191 if (__DEV__) {2192 setCurrentDebugFiberInDEV(fiber);2193 invokeGuardedCallback(2194 null,2195 commitPassiveMountOnFiber,2196 null,2197 root,2198 fiber,2199 );2200 if (hasCaughtError()) {2201 const error = clearCaughtError();2202 captureCommitPhaseError(fiber, fiber.return, error);2203 }2204 resetCurrentDebugFiberInDEV();2205 } else {2206 try {2207 commitPassiveMountOnFiber(root, fiber);2208 } catch (error) {2209 captureCommitPhaseError(fiber, fiber.return, error);2210 }2211 }2212 }2213 if (enableProfilerTimer && enableProfilerCommitHooks) {2214 if (fiber.tag === Profiler) {2215 // Bubble times to the next nearest ancestor Profiler.2216 // After we process that Profiler, we'll bubble further up.2217 if (prevProfilerOnStack !== null) {2218 prevProfilerOnStack.stateNode.passiveEffectDuration +=2219 fiber.stateNode.passiveEffectDuration;2220 }2221 nearestProfilerOnStack = prevProfilerOnStack;2222 }2223 }2224 fiber = fiber.sibling;2225 }2226}2227function flushPassiveUnmountEffects(firstChild: Fiber): void {2228 let fiber = firstChild;2229 while (fiber !== null) {2230 const deletions = fiber.deletions;2231 if (deletions !== null) {2232 for (let i = 0; i < deletions.length; i++) {2233 const fiberToDelete = deletions[i];2234 flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, fiber);2235 // Now that passive effects have been processed, it's safe to detach lingering pointers.2236 detachFiberAfterEffects(fiberToDelete);2237 }2238 }2239 const child = fiber.child;2240 if (child !== null) {2241 // If any children have passive effects then traverse the subtree.2242 // Note that this requires checking subtreeFlags of the current Fiber,2243 // rather than the subtreeFlags/effectsTag of the first child,2244 // since that would not cover passive effects in siblings.2245 const passiveFlags = fiber.subtreeFlags & PassiveMask;2246 if (passiveFlags !== NoFlags) {2247 flushPassiveUnmountEffects(child);2248 }2249 }2250 const primaryFlags = fiber.flags & Passive;2251 if (primaryFlags !== NoFlags) {2252 setCurrentDebugFiberInDEV(fiber);2253 commitPassiveUnmountOnFiber(fiber);2254 resetCurrentDebugFiberInDEV();2255 }2256 fiber = fiber.sibling;2257 }2258}2259function flushPassiveUnmountEffectsInsideOfDeletedTree(2260 fiberToDelete: Fiber,2261 nearestMountedAncestor: Fiber,2262): void {2263 if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {2264 // If any children have passive effects then traverse the subtree.2265 // Note that this requires checking subtreeFlags of the current Fiber,2266 // rather than the subtreeFlags/effectsTag of the first child,2267 // since that would not cover passive effects in siblings.2268 let child = fiberToDelete.child;2269 while (child !== null) {2270 flushPassiveUnmountEffectsInsideOfDeletedTree(2271 child,2272 nearestMountedAncestor,2273 );2274 child = child.sibling;2275 }2276 }2277 if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {2278 setCurrentDebugFiberInDEV(fiberToDelete);2279 commitPassiveUnmountInsideDeletedTreeOnFiber(2280 fiberToDelete,2281 nearestMountedAncestor,2282 );2283 resetCurrentDebugFiberInDEV();2284 }2285}2286function flushPassiveEffectsImpl() {2287 if (rootWithPendingPassiveEffects === null) {2288 return false;2289 }2290 const root = rootWithPendingPassiveEffects;2291 const lanes = pendingPassiveEffectsLanes;2292 rootWithPendingPassiveEffects = null;2293 pendingPassiveEffectsLanes = NoLanes;2294 invariant(2295 (executionContext & (RenderContext | CommitContext)) === NoContext,2296 'Cannot flush passive effects while already rendering.',2297 );2298 if (__DEV__) {2299 if (enableDebugTracing) {2300 logPassiveEffectsStarted(lanes);2301 }2302 }2303 if (enableSchedulingProfiler) {2304 markPassiveEffectsStarted(lanes);2305 }2306 if (__DEV__) {2307 isFlushingPassiveEffects = true;2308 }2309 const prevExecutionContext = executionContext;2310 executionContext |= CommitContext;2311 const prevInteractions = pushInteractions(root);2312 // It's important that ALL pending passive effect destroy functions are called2313 // before ANY passive effect create functions are called.2314 // Otherwise effects in sibling components might interfere with each other.2315 // e.g. a destroy function in one component may unintentionally override a ref2316 // value set by a create function in another component.2317 // Layout effects have the same constraint.2318 flushPassiveUnmountEffects(root.current);2319 flushPassiveMountEffects(root, root.current);2320 if (__DEV__) {2321 if (enableDebugTracing) {2322 logPassiveEffectsStopped();2323 }2324 }2325 if (enableSchedulingProfiler) {2326 markPassiveEffectsStopped();2327 }2328 if (__DEV__ && enableDoubleInvokingEffects) {2329 commitDoubleInvokeEffectsInDEV(root.current, true);2330 }2331 if (__DEV__) {2332 isFlushingPassiveEffects = false;2333 }2334 if (enableSchedulerTracing) {2335 popInteractions(((prevInteractions: any): Set<Interaction>));2336 finishPendingInteractions(root, lanes);2337 }2338 executionContext = prevExecutionContext;2339 flushSyncCallbackQueue();2340 // If additional passive effects were scheduled, increment a counter. If this2341 // exceeds the limit, we'll fire a warning.2342 nestedPassiveUpdateCount =2343 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;2344 return true;2345}2346export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {2347 return (2348 legacyErrorBoundariesThatAlreadyFailed !== null &&2349 legacyErrorBoundariesThatAlreadyFailed.has(instance)2350 );2351}2352export function markLegacyErrorBoundaryAsFailed(instance: mixed) {2353 if (legacyErrorBoundariesThatAlreadyFailed === null) {2354 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);2355 } else {2356 legacyErrorBoundariesThatAlreadyFailed.add(instance);2357 }2358}2359function prepareToThrowUncaughtError(error: mixed) {2360 if (!hasUncaughtError) {2361 hasUncaughtError = true;2362 firstUncaughtError = error;2363 }2364}2365export const onUncaughtError = prepareToThrowUncaughtError;2366function captureCommitPhaseErrorOnRoot(2367 rootFiber: Fiber,2368 sourceFiber: Fiber,2369 error: mixed,2370) {2371 const errorInfo = createCapturedValue(error, sourceFiber);2372 const update = createRootErrorUpdate(rootFiber, errorInfo, (SyncLane: Lane));2373 enqueueUpdate(rootFiber, update);2374 const eventTime = requestEventTime();2375 const root = markUpdateLaneFromFiberToRoot(rootFiber, (SyncLane: Lane));2376 if (root !== null) {2377 markRootUpdated(root, SyncLane, eventTime);2378 ensureRootIsScheduled(root, eventTime);2379 schedulePendingInteractions(root, SyncLane);2380 }2381}2382export function captureCommitPhaseError(2383 sourceFiber: Fiber,2384 nearestMountedAncestor: Fiber | null,2385 error: mixed,2386) {2387 if (sourceFiber.tag === HostRoot) {2388 // Error was thrown at the root. There is no parent, so the root2389 // itself should capture it.2390 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);2391 return;2392 }2393 let fiber = null;2394 if (skipUnmountedBoundaries) {2395 fiber = nearestMountedAncestor;2396 } else {2397 fiber = sourceFiber.return;2398 }2399 while (fiber !== null) {2400 if (fiber.tag === HostRoot) {2401 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);2402 return;2403 } else if (fiber.tag === ClassComponent) {2404 const ctor = fiber.type;2405 const instance = fiber.stateNode;2406 if (2407 typeof ctor.getDerivedStateFromError === 'function' ||2408 (typeof instance.componentDidCatch === 'function' &&2409 !isAlreadyFailedLegacyErrorBoundary(instance))2410 ) {2411 const errorInfo = createCapturedValue(error, sourceFiber);2412 const update = createClassErrorUpdate(2413 fiber,2414 errorInfo,2415 (SyncLane: Lane),2416 );2417 enqueueUpdate(fiber, update);2418 const eventTime = requestEventTime();2419 const root = markUpdateLaneFromFiberToRoot(fiber, (SyncLane: Lane));2420 if (root !== null) {2421 markRootUpdated(root, SyncLane, eventTime);2422 ensureRootIsScheduled(root, eventTime);2423 schedulePendingInteractions(root, SyncLane);2424 }2425 return;2426 }2427 }2428 fiber = fiber.return;2429 }2430}2431export function pingSuspendedRoot(2432 root: FiberRoot,2433 wakeable: Wakeable,2434 pingedLanes: Lanes,2435) {2436 const pingCache = root.pingCache;2437 if (pingCache !== null) {2438 // The wakeable resolved, so we no longer need to memoize, because it will2439 // never be thrown again.2440 pingCache.delete(wakeable);2441 }2442 const eventTime = requestEventTime();2443 markRootPinged(root, pingedLanes, eventTime);2444 if (2445 workInProgressRoot === root &&2446 isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)2447 ) {2448 // Received a ping at the same priority level at which we're currently2449 // rendering. We might want to restart this render. This should mirror2450 // the logic of whether or not a root suspends once it completes.2451 // TODO: If we're rendering sync either due to Sync, Batched or expired,2452 // we should probably never restart.2453 // If we're suspended with delay, or if it's a retry, we'll always suspend2454 // so we can always restart.2455 if (2456 workInProgressRootExitStatus === RootSuspendedWithDelay ||2457 (workInProgressRootExitStatus === RootSuspended &&2458 includesOnlyRetries(workInProgressRootRenderLanes) &&2459 now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)2460 ) {2461 // Restart from the root.2462 prepareFreshStack(root, NoLanes);2463 } else {2464 // Even though we can't restart right now, we might get an2465 // opportunity later. So we mark this render as having a ping.2466 workInProgressRootPingedLanes = mergeLanes(2467 workInProgressRootPingedLanes,2468 pingedLanes,2469 );2470 }2471 }2472 ensureRootIsScheduled(root, eventTime);2473 schedulePendingInteractions(root, pingedLanes);2474}2475function retryTimedOutBoundary(boundaryFiber: Fiber, retryLane: Lane) {2476 // The boundary fiber (a Suspense component or SuspenseList component)2477 // previously was rendered in its fallback state. One of the promises that2478 // suspended it has resolved, which means at least part of the tree was2479 // likely unblocked. Try rendering again, at a new expiration time.2480 if (retryLane === NoLane) {2481 retryLane = requestRetryLane(boundaryFiber);2482 }2483 // TODO: Special case idle priority?2484 const eventTime = requestEventTime();2485 const root = markUpdateLaneFromFiberToRoot(boundaryFiber, retryLane);2486 if (root !== null) {2487 markRootUpdated(root, retryLane, eventTime);2488 ensureRootIsScheduled(root, eventTime);2489 schedulePendingInteractions(root, retryLane);2490 }2491}2492export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {2493 const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2494 let retryLane = NoLane;2495 if (suspenseState !== null) {2496 retryLane = suspenseState.retryLane;2497 }2498 retryTimedOutBoundary(boundaryFiber, retryLane);2499}2500export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {2501 let retryLane = NoLane; // Default2502 let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;2503 if (enableSuspenseServerRenderer) {2504 switch (boundaryFiber.tag) {2505 case SuspenseComponent:2506 retryCache = boundaryFiber.stateNode;2507 const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2508 if (suspenseState !== null) {2509 retryLane = suspenseState.retryLane;2510 }2511 break;2512 case SuspenseListComponent:2513 retryCache = boundaryFiber.stateNode;2514 break;2515 default:2516 invariant(2517 false,2518 'Pinged unknown suspense boundary type. ' +2519 'This is probably a bug in React.',2520 );2521 }2522 } else {2523 retryCache = boundaryFiber.stateNode;2524 }2525 if (retryCache !== null) {2526 // The wakeable resolved, so we no longer need to memoize, because it will2527 // never be thrown again.2528 retryCache.delete(wakeable);2529 }2530 retryTimedOutBoundary(boundaryFiber, retryLane);2531}2532// Computes the next Just Noticeable Difference (JND) boundary.2533// The theory is that a person can't tell the difference between small differences in time.2534// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable2535// difference in the experience. However, waiting for longer might mean that we can avoid2536// showing an intermediate loading state. The longer we have already waited, the harder it2537// is to tell small differences in time. Therefore, the longer we've already waited,2538// the longer we can wait additionally. At some point we have to give up though.2539// We pick a train model where the next boundary commits at a consistent schedule.2540// These particular numbers are vague estimates. We expect to adjust them based on research.2541function jnd(timeElapsed: number) {2542 return timeElapsed < 1202543 ? 1202544 : timeElapsed < 4802545 ? 4802546 : timeElapsed < 10802547 ? 10802548 : timeElapsed < 19202549 ? 19202550 : timeElapsed < 30002551 ? 30002552 : timeElapsed < 43202553 ? 43202554 : ceil(timeElapsed / 1960) * 1960;2555}2556function checkForNestedUpdates() {2557 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {2558 nestedUpdateCount = 0;2559 rootWithNestedUpdates = null;2560 invariant(2561 false,2562 'Maximum update depth exceeded. This can happen when a component ' +2563 'repeatedly calls setState inside componentWillUpdate or ' +2564 'componentDidUpdate. React limits the number of nested updates to ' +2565 'prevent infinite loops.',2566 );2567 }2568 if (__DEV__) {2569 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {2570 nestedPassiveUpdateCount = 0;2571 console.error(2572 'Maximum update depth exceeded. This can happen when a component ' +2573 "calls setState inside useEffect, but useEffect either doesn't " +2574 'have a dependency array, or one of the dependencies changes on ' +2575 'every render.',2576 );2577 }2578 }2579}2580function flushRenderPhaseStrictModeWarningsInDEV() {2581 if (__DEV__) {2582 ReactStrictModeWarnings.flushLegacyContextWarning();2583 if (warnAboutDeprecatedLifecycles) {2584 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();2585 }2586 }2587}2588function commitDoubleInvokeEffectsInDEV(2589 fiber: Fiber,2590 hasPassiveEffects: boolean,2591) {2592 if (__DEV__ && enableDoubleInvokingEffects) {2593 setCurrentDebugFiberInDEV(fiber);2594 invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);2595 if (hasPassiveEffects) {2596 invokeEffectsInDev(2597 fiber,2598 MountPassiveDev,2599 invokePassiveEffectUnmountInDEV,2600 );2601 }2602 invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV);2603 if (hasPassiveEffects) {2604 invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);2605 }2606 resetCurrentDebugFiberInDEV();2607 }2608}2609function invokeEffectsInDev(2610 firstChild: Fiber,2611 fiberFlags: Flags,2612 invokeEffectFn: (fiber: Fiber) => void,2613): void {2614 if (__DEV__ && enableDoubleInvokingEffects) {2615 let fiber = firstChild;2616 while (fiber !== null) {2617 if (fiber.child !== null) {2618 const primarySubtreeFlag = fiber.subtreeFlags & fiberFlags;2619 if (primarySubtreeFlag !== NoFlags) {2620 invokeEffectsInDev(fiber.child, fiberFlags, invokeEffectFn);2621 }2622 }2623 if ((fiber.flags & fiberFlags) !== NoFlags) {2624 invokeEffectFn(fiber);2625 }2626 fiber = fiber.sibling;2627 }2628 }2629}2630let didWarnStateUpdateForNotYetMountedComponent: Set<string> | null = null;2631function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {2632 if (__DEV__) {2633 if ((executionContext & RenderContext) !== NoContext) {2634 // We let the other warning about render phase updates deal with this one.2635 return;2636 }2637 if (!(fiber.mode & (BlockingMode | ConcurrentMode))) {2638 return;2639 }2640 const tag = fiber.tag;2641 if (2642 tag !== IndeterminateComponent &&2643 tag !== HostRoot &&2644 tag !== ClassComponent &&2645 tag !== FunctionComponent &&2646 tag !== ForwardRef &&2647 tag !== MemoComponent &&2648 tag !== SimpleMemoComponent &&2649 tag !== Block2650 ) {2651 // Only warn for user-defined components, not internal ones like Suspense.2652 return;2653 }2654 // We show the whole stack but dedupe on the top component's name because2655 // the problematic code almost always lies inside that component.2656 const componentName = getComponentName(fiber.type) || 'ReactComponent';2657 if (didWarnStateUpdateForNotYetMountedComponent !== null) {2658 if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {2659 return;2660 }2661 didWarnStateUpdateForNotYetMountedComponent.add(componentName);2662 } else {2663 didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);2664 }2665 const previousFiber = ReactCurrentFiberCurrent;2666 try {2667 setCurrentDebugFiberInDEV(fiber);2668 console.error(2669 "Can't perform a React state update on a component that hasn't mounted yet. " +2670 'This indicates that you have a side-effect in your render function that ' +2671 'asynchronously later calls tries to update the component. Move this work to ' +2672 'useEffect instead.',2673 );2674 } finally {2675 if (previousFiber) {2676 setCurrentDebugFiberInDEV(fiber);2677 } else {2678 resetCurrentDebugFiberInDEV();2679 }2680 }2681 }2682}2683let didWarnStateUpdateForUnmountedComponent: Set<string> | null = null;2684function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {2685 if (__DEV__) {2686 const tag = fiber.tag;2687 if (2688 tag !== HostRoot &&2689 tag !== ClassComponent &&2690 tag !== FunctionComponent &&2691 tag !== ForwardRef &&2692 tag !== MemoComponent &&2693 tag !== SimpleMemoComponent &&2694 tag !== Block2695 ) {2696 // Only warn for user-defined components, not internal ones like Suspense.2697 return;2698 }2699 if ((fiber.flags & PassiveStatic) !== NoFlags) {2700 const updateQueue: FunctionComponentUpdateQueue | null = (fiber.updateQueue: any);2701 if (updateQueue !== null) {2702 const lastEffect = updateQueue.lastEffect;2703 if (lastEffect !== null) {2704 const firstEffect = lastEffect.next;2705 let effect = firstEffect;2706 do {2707 if (effect.destroy !== undefined) {2708 if ((effect.tag & HookPassive) !== NoHookEffect) {2709 return;2710 }2711 }2712 effect = effect.next;2713 } while (effect !== firstEffect);2714 }2715 }2716 }2717 // We show the whole stack but dedupe on the top component's name because2718 // the problematic code almost always lies inside that component.2719 const componentName = getComponentName(fiber.type) || 'ReactComponent';2720 if (didWarnStateUpdateForUnmountedComponent !== null) {2721 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {2722 return;2723 }2724 didWarnStateUpdateForUnmountedComponent.add(componentName);2725 } else {2726 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);2727 }2728 if (isFlushingPassiveEffects) {2729 // Do not warn if we are currently flushing passive effects!2730 //2731 // React can't directly detect a memory leak, but there are some clues that warn about one.2732 // One of these clues is when an unmounted React component tries to update its state.2733 // For example, if a component forgets to remove an event listener when unmounting,2734 // that listener may be called later and try to update state,2735 // at which point React would warn about the potential leak.2736 //2737 // Warning signals are the most useful when they're strong.2738 // (So we should avoid false positive warnings.)2739 // Updating state from within an effect cleanup function is sometimes a necessary pattern, e.g.:2740 // 1. Updating an ancestor that a component had registered itself with on mount.2741 // 2. Resetting state when a component is hidden after going offscreen.2742 } else {2743 const previousFiber = ReactCurrentFiberCurrent;2744 try {2745 setCurrentDebugFiberInDEV(fiber);2746 console.error(2747 "Can't perform a React state update on an unmounted component. This " +2748 'is a no-op, but it indicates a memory leak in your application. To ' +2749 'fix, cancel all subscriptions and asynchronous tasks in %s.',2750 tag === ClassComponent2751 ? 'the componentWillUnmount method'2752 : 'a useEffect cleanup function',2753 );2754 } finally {2755 if (previousFiber) {2756 setCurrentDebugFiberInDEV(fiber);2757 } else {2758 resetCurrentDebugFiberInDEV();2759 }2760 }2761 }2762 }2763}2764let beginWork;2765if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {2766 const dummyFiber = null;2767 beginWork = (current, unitOfWork, lanes) => {2768 // If a component throws an error, we replay it again in a synchronously2769 // dispatched event, so that the debugger will treat it as an uncaught2770 // error See ReactErrorUtils for more information.2771 // Before entering the begin phase, copy the work-in-progress onto a dummy2772 // fiber. If beginWork throws, we'll use this to reset the state.2773 const originalWorkInProgressCopy = assignFiberPropertiesInDEV(2774 dummyFiber,2775 unitOfWork,2776 );2777 try {2778 return originalBeginWork(current, unitOfWork, lanes);2779 } catch (originalError) {2780 if (2781 originalError !== null &&2782 typeof originalError === 'object' &&2783 typeof originalError.then === 'function'2784 ) {2785 // Don't replay promises. Treat everything else like an error.2786 throw originalError;2787 }2788 // Keep this code in sync with handleError; any changes here must have2789 // corresponding changes there.2790 resetContextDependencies();2791 resetHooksAfterThrow();2792 // Don't reset current debug fiber, since we're about to work on the2793 // same fiber again.2794 // Unwind the failed stack frame2795 unwindInterruptedWork(unitOfWork);2796 // Restore the original properties of the fiber.2797 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);2798 if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {2799 // Reset the profiler timer.2800 startProfilerTimer(unitOfWork);2801 }2802 // Run beginWork again.2803 invokeGuardedCallback(2804 null,2805 originalBeginWork,2806 null,2807 current,2808 unitOfWork,2809 lanes,2810 );2811 if (hasCaughtError()) {2812 const replayError = clearCaughtError();2813 // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.2814 // Rethrow this error instead of the original one.2815 throw replayError;2816 } else {2817 // This branch is reachable if the render phase is impure.2818 throw originalError;2819 }2820 }2821 };2822} else {2823 beginWork = originalBeginWork;2824}2825let didWarnAboutUpdateInRender = false;2826let didWarnAboutUpdateInRenderForAnotherComponent;2827if (__DEV__) {2828 didWarnAboutUpdateInRenderForAnotherComponent = new Set();2829}2830function warnAboutRenderPhaseUpdatesInDEV(fiber) {2831 if (__DEV__) {2832 if (2833 ReactCurrentDebugFiberIsRenderingInDEV &&2834 (executionContext & RenderContext) !== NoContext &&2835 !getIsUpdatingOpaqueValueInRenderPhaseInDEV()2836 ) {2837 switch (fiber.tag) {2838 case FunctionComponent:2839 case ForwardRef:2840 case SimpleMemoComponent: {2841 const renderingComponentName =2842 (workInProgress && getComponentName(workInProgress.type)) ||2843 'Unknown';2844 // Dedupe by the rendering component because it's the one that needs to be fixed.2845 const dedupeKey = renderingComponentName;2846 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {2847 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);2848 const setStateComponentName =2849 getComponentName(fiber.type) || 'Unknown';2850 console.error(2851 'Cannot update a component (`%s`) while rendering a ' +2852 'different component (`%s`). To locate the bad setState() call inside `%s`, ' +2853 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render',2854 setStateComponentName,2855 renderingComponentName,2856 renderingComponentName,2857 );2858 }2859 break;2860 }2861 case ClassComponent: {2862 if (!didWarnAboutUpdateInRender) {2863 console.error(2864 'Cannot update during an existing state transition (such as ' +2865 'within `render`). Render methods should be a pure ' +2866 'function of props and state.',2867 );2868 didWarnAboutUpdateInRender = true;2869 }2870 break;2871 }2872 }2873 }2874 }2875}2876// a 'shared' variable that changes when act() opens/closes in tests.2877export const IsThisRendererActing = {current: (false: boolean)};2878export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {2879 if (__DEV__) {2880 if (2881 warnsIfNotActing === true &&2882 IsSomeRendererActing.current === true &&2883 IsThisRendererActing.current !== true2884 ) {2885 const previousFiber = ReactCurrentFiberCurrent;2886 try {2887 setCurrentDebugFiberInDEV(fiber);2888 console.error(2889 "It looks like you're using the wrong act() around your test interactions.\n" +2890 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' +2891 '// for react-dom:\n' +2892 // Break up imports to avoid accidentally parsing them as dependencies.2893 'import {act} fr' +2894 "om 'react-dom/test-utils';\n" +2895 '// ...\n' +2896 'act(() => ...);\n\n' +2897 '// for react-test-renderer:\n' +2898 // Break up imports to avoid accidentally parsing them as dependencies.2899 'import TestRenderer fr' +2900 "om react-test-renderer';\n" +2901 'const {act} = TestRenderer;\n' +2902 '// ...\n' +2903 'act(() => ...);',2904 );2905 } finally {2906 if (previousFiber) {2907 setCurrentDebugFiberInDEV(fiber);2908 } else {2909 resetCurrentDebugFiberInDEV();2910 }2911 }2912 }2913 }2914}2915export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {2916 if (__DEV__) {2917 if (2918 warnsIfNotActing === true &&2919 (fiber.mode & StrictMode) !== NoMode &&2920 IsSomeRendererActing.current === false &&2921 IsThisRendererActing.current === false2922 ) {2923 console.error(2924 'An update to %s ran an effect, but was not wrapped in act(...).\n\n' +2925 'When testing, code that causes React state updates should be ' +2926 'wrapped into act(...):\n\n' +2927 'act(() => {\n' +2928 ' /* fire events that update state */\n' +2929 '});\n' +2930 '/* assert on the output */\n\n' +2931 "This ensures that you're testing the behavior the user would see " +2932 'in the browser.' +2933 ' Learn more at https://reactjs.org/link/wrap-tests-with-act',2934 getComponentName(fiber.type),2935 );2936 }2937 }2938}2939function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {2940 if (__DEV__) {2941 if (2942 warnsIfNotActing === true &&2943 executionContext === NoContext &&2944 IsSomeRendererActing.current === false &&2945 IsThisRendererActing.current === false2946 ) {2947 const previousFiber = ReactCurrentFiberCurrent;2948 try {2949 setCurrentDebugFiberInDEV(fiber);2950 console.error(2951 'An update to %s inside a test was not wrapped in act(...).\n\n' +2952 'When testing, code that causes React state updates should be ' +2953 'wrapped into act(...):\n\n' +2954 'act(() => {\n' +2955 ' /* fire events that update state */\n' +2956 '});\n' +2957 '/* assert on the output */\n\n' +2958 "This ensures that you're testing the behavior the user would see " +2959 'in the browser.' +2960 ' Learn more at https://reactjs.org/link/wrap-tests-with-act',2961 getComponentName(fiber.type),2962 );2963 } finally {2964 if (previousFiber) {2965 setCurrentDebugFiberInDEV(fiber);2966 } else {2967 resetCurrentDebugFiberInDEV();2968 }2969 }2970 }2971 }2972}2973export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV;2974// In tests, we want to enforce a mocked scheduler.2975let didWarnAboutUnmockedScheduler = false;2976// TODO Before we release concurrent mode, revisit this and decide whether a mocked2977// scheduler is the actual recommendation. The alternative could be a testing build,2978// a new lib, or whatever; we dunno just yet. This message is for early adopters2979// to get their tests right.2980export function warnIfUnmockedScheduler(fiber: Fiber) {2981 if (__DEV__) {2982 if (2983 didWarnAboutUnmockedScheduler === false &&2984 Scheduler.unstable_flushAllWithoutAsserting === undefined2985 ) {2986 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) {2987 didWarnAboutUnmockedScheduler = true;2988 console.error(2989 'In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' +2990 'to guarantee consistent behaviour across tests and browsers. ' +2991 'For example, with jest: \n' +2992 // Break up requires to avoid accidentally parsing them as dependencies.2993 "jest.mock('scheduler', () => require" +2994 "('scheduler/unstable_mock'));\n\n" +2995 'For more info, visit https://reactjs.org/link/mock-scheduler',2996 );2997 } else if (warnAboutUnmockedScheduler === true) {2998 didWarnAboutUnmockedScheduler = true;2999 console.error(3000 'Starting from React v18, the "scheduler" module will need to be mocked ' +3001 'to guarantee consistent behaviour across tests and browsers. ' +3002 'For example, with jest: \n' +3003 // Break up requires to avoid accidentally parsing them as dependencies.3004 "jest.mock('scheduler', () => require" +3005 "('scheduler/unstable_mock'));\n\n" +3006 'For more info, visit https://reactjs.org/link/mock-scheduler',3007 );3008 }3009 }3010 }3011}3012function computeThreadID(root: FiberRoot, lane: Lane | Lanes) {3013 // Interaction threads are unique per root and expiration time.3014 // NOTE: Intentionally unsound cast. All that matters is that it's a number3015 // and it represents a batch of work. Could make a helper function instead,3016 // but meh this is fine for now.3017 return (lane: any) * 1000 + root.interactionThreadID;3018}3019export function markSpawnedWork(lane: Lane | Lanes) {3020 if (!enableSchedulerTracing) {3021 return;3022 }3023 if (spawnedWorkDuringRender === null) {3024 spawnedWorkDuringRender = [lane];3025 } else {3026 spawnedWorkDuringRender.push(lane);3027 }3028}3029function scheduleInteractions(3030 root: FiberRoot,3031 lane: Lane | Lanes,3032 interactions: Set<Interaction>,3033) {3034 if (!enableSchedulerTracing) {3035 return;3036 }3037 if (interactions.size > 0) {3038 const pendingInteractionMap = root.pendingInteractionMap;3039 const pendingInteractions = pendingInteractionMap.get(lane);3040 if (pendingInteractions != null) {3041 interactions.forEach(interaction => {3042 if (!pendingInteractions.has(interaction)) {3043 // Update the pending async work count for previously unscheduled interaction.3044 interaction.__count++;3045 }3046 pendingInteractions.add(interaction);3047 });3048 } else {3049 pendingInteractionMap.set(lane, new Set(interactions));3050 // Update the pending async work count for the current interactions.3051 interactions.forEach(interaction => {3052 interaction.__count++;3053 });3054 }3055 const subscriber = __subscriberRef.current;3056 if (subscriber !== null) {3057 const threadID = computeThreadID(root, lane);3058 subscriber.onWorkScheduled(interactions, threadID);3059 }3060 }3061}3062function schedulePendingInteractions(root: FiberRoot, lane: Lane | Lanes) {3063 // This is called when work is scheduled on a root.3064 // It associates the current interactions with the newly-scheduled expiration.3065 // They will be restored when that expiration is later committed.3066 if (!enableSchedulerTracing) {3067 return;3068 }3069 scheduleInteractions(root, lane, __interactionsRef.current);3070}3071function startWorkOnPendingInteractions(root: FiberRoot, lanes: Lanes) {3072 // This is called when new work is started on a root.3073 if (!enableSchedulerTracing) {3074 return;3075 }3076 // Determine which interactions this batch of work currently includes, So that...
ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js
...212 if ( // Check if we're inside unbatchedUpdates213 (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering214 (executionContext & (RenderContext | CommitContext)) === NoContext) {215 // Register pending interactions on the root to avoid losing traced interaction data.216 schedulePendingInteractions(root, lane); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed217 // root inside of batchedUpdates should be synchronous, but layout updates218 // should be deferred until the end of the batch.219 performSyncWorkOnRoot(root);220 } else {221 ensureRootIsScheduled(root, eventTime);222 schedulePendingInteractions(root, lane);223 if (executionContext === NoContext) {224 // Flush the synchronous work now, unless we're already working or inside225 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of226 // scheduleCallbackForFiber to preserve the ability to schedule a callback227 // without immediately flushing it. We only do this for user-initiated228 // updates, to preserve historical behavior of legacy mode.229 resetRenderTimer();230 flushSyncCallbackQueue();231 }232 }233 } else {234 // Schedule a discrete update but only if it's not Sync.235 if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered236 // discrete, even inside a discrete event.237 priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority$1)) {238 // This is the result of a discrete event. Track the lowest priority239 // discrete update per root so we can flush them early, if needed.240 if (rootsWithPendingDiscreteUpdates === null) {241 rootsWithPendingDiscreteUpdates = new Set([root]);242 } else {243 rootsWithPendingDiscreteUpdates.add(root);244 }245 } // Schedule other updates after in case the callback is sync.246 ensureRootIsScheduled(root, eventTime);247 schedulePendingInteractions(root, lane);248 } // We use this when assigning a lane for a transition inside249 // `requestUpdateLane`. We assume it's the same as the root being updated,250 // since in the common case of a single root app it probably is. If it's not251 // the same root, then it's not a huge deal, we just might batch more stuff252 // together more than necessary.253 mostRecentlyUpdatedRoot = root;254 } // This is split into a separate function so we can mark a fiber with pending255 // work without treating it as a typical update that originates from an event;256 // e.g. retrying a Suspense boundary isn't an update, but it does schedule work257 // on a fiber.258 function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {259 // Update the source fiber's lanes260 sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);261 var alternate = sourceFiber.alternate;262 if (alternate !== null) {263 alternate.lanes = mergeLanes(alternate.lanes, lane);264 }265 {266 if (alternate === null && (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags) {267 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);268 }269 } // Walk the parent path to the root and update the child expiration time.270 var node = sourceFiber;271 var parent = sourceFiber.return;272 while (parent !== null) {273 parent.childLanes = mergeLanes(parent.childLanes, lane);274 alternate = parent.alternate;275 if (alternate !== null) {276 alternate.childLanes = mergeLanes(alternate.childLanes, lane);277 } else {278 {279 if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {280 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);281 }282 }283 }284 node = parent;285 parent = parent.return;286 }287 if (node.tag === HostRoot) {288 var root = node.stateNode;289 return root;290 } else {291 return null;292 }293 } // Use this function to schedule a task for a root. There's only one task per294 // root; if a task was already scheduled, we'll check to make sure the priority295 // of the existing task is the same as the priority of the next level that the296 // root has work on. This function is called on every update, and right before297 // exiting a task.298 function ensureRootIsScheduled(root, currentTime) {299 var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as300 // expired so we know to work on those next.301 markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority.302 var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); // This returns the priority level computed during the `getNextLanes` call.303 var newCallbackPriority = returnNextLanesPriority();304 if (nextLanes === NoLanes) {305 // Special case: There's nothing to work on.306 if (existingCallbackNode !== null) {307 cancelCallback(existingCallbackNode);308 root.callbackNode = null;309 root.callbackPriority = NoLanePriority;310 }311 return;312 } // Check if there's an existing task. We may be able to reuse it.313 if (existingCallbackNode !== null) {314 var existingCallbackPriority = root.callbackPriority;315 if (existingCallbackPriority === newCallbackPriority) {316 // The priority hasn't changed. We can reuse the existing task. Exit.317 return;318 } // The priority changed. Cancel the existing callback. We'll schedule a new319 // one below.320 cancelCallback(existingCallbackNode);321 } // Schedule a new callback.322 var newCallbackNode;323 if (newCallbackPriority === SyncLanePriority) {324 // Special case: Sync React callbacks are scheduled on a special325 // internal queue326 newCallbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));327 } else if (newCallbackPriority === SyncBatchedLanePriority) {328 newCallbackNode = scheduleCallback(ImmediatePriority$1, performSyncWorkOnRoot.bind(null, root));329 } else {330 var schedulerPriorityLevel = lanePriorityToSchedulerPriority(newCallbackPriority);331 newCallbackNode = scheduleCallback(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));332 }333 root.callbackPriority = newCallbackPriority;334 root.callbackNode = newCallbackNode;335 } // This is the entry point for every concurrent task, i.e. anything that336 // goes through Scheduler.337 function performConcurrentWorkOnRoot(root) {338 // Since we know we're in a React event, we can clear the current339 // event time. The next update will compute a new event time.340 currentEventTime = NoTimestamp;341 currentEventWipLanes = NoLanes;342 currentEventPendingLanes = NoLanes;343 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {344 {345 throw Error( "Should not already be working." );346 }347 } // Flush any pending passive effects before deciding which lanes to work on,348 // in case they schedule additional work.349 var originalCallbackNode = root.callbackNode;350 var didFlushPassiveEffects = flushPassiveEffects();351 if (didFlushPassiveEffects) {352 // Something in the passive effect phase may have canceled the current task.353 // Check if the task node for this root was changed.354 if (root.callbackNode !== originalCallbackNode) {355 // The current task was canceled. Exit. We don't need to call356 // `ensureRootIsScheduled` because the check above implies either that357 // there's a new task, or that there's no remaining work on this root.358 return null;359 }360 } // Determine the next expiration time to work on, using the fields stored361 // on the root.362 var lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);363 if (lanes === NoLanes) {364 // Defensive coding. This is never expected to happen.365 return null;366 }367 var exitStatus = renderRootConcurrent(root, lanes);368 if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {369 // The render included lanes that were updated during the render phase.370 // For example, when unhiding a hidden tree, we include all the lanes371 // that were previously skipped when the tree was hidden. That set of372 // lanes is a superset of the lanes we started rendering with.373 //374 // So we'll throw out the current work and restart.375 prepareFreshStack(root, NoLanes);376 } else if (exitStatus !== RootIncomplete) {377 if (exitStatus === RootErrored) {378 executionContext |= RetryAfterError; // If an error occurred during hydration,379 // discard server response and fall back to client side render.380 if (root.hydrate) {381 root.hydrate = false;382 clearContainer(root.containerInfo);383 } // If something threw an error, try rendering one more time. We'll render384 // synchronously to block concurrent data mutations, and we'll includes385 // all pending updates are included. If it still fails after the second386 // attempt, we'll give up and commit the resulting tree.387 lanes = getLanesToRetrySynchronouslyOnError(root);388 if (lanes !== NoLanes) {389 exitStatus = renderRootSync(root, lanes);390 }391 }392 if (exitStatus === RootFatalErrored) {393 var fatalError = workInProgressRootFatalError;394 prepareFreshStack(root, NoLanes);395 markRootSuspended$1(root, lanes);396 ensureRootIsScheduled(root, now());397 throw fatalError;398 } // We now have a consistent tree. The next step is either to commit it,399 // or, if something suspended, wait to commit it after a timeout.400 var finishedWork = root.current.alternate;401 root.finishedWork = finishedWork;402 root.finishedLanes = lanes;403 finishConcurrentRender(root, exitStatus, lanes);404 }405 ensureRootIsScheduled(root, now());406 if (root.callbackNode === originalCallbackNode) {407 // The task node scheduled for this root is the same one that's408 // currently executed. Need to return a continuation.409 return performConcurrentWorkOnRoot.bind(null, root);410 }411 return null;412 }413 function finishConcurrentRender(root, exitStatus, lanes) {414 switch (exitStatus) {415 case RootIncomplete:416 case RootFatalErrored:417 {418 {419 {420 throw Error( "Root did not complete. This is a bug in React." );421 }422 }423 }424 // Flow knows about invariant, so it complains if I add a break425 // statement, but eslint doesn't know about invariant, so it complains426 // if I do. eslint-disable-next-line no-fallthrough427 case RootErrored:428 {429 // We should have already attempted to retry this tree. If we reached430 // this point, it errored again. Commit it.431 commitRoot(root);432 break;433 }434 case RootSuspended:435 {436 markRootSuspended$1(root, lanes); // We have an acceptable loading state. We need to figure out if we437 // should immediately commit it or wait a bit.438 if (includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope439 !shouldForceFlushFallbacksInDEV()) {440 // This render only included retries, no updates. Throttle committing441 // retries so that we don't show too many loading states too quickly.442 var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now(); // Don't bother with a very short suspense time.443 if (msUntilTimeout > 10) {444 var nextLanes = getNextLanes(root, NoLanes);445 if (nextLanes !== NoLanes) {446 // There's additional work on this root.447 break;448 }449 var suspendedLanes = root.suspendedLanes;450 if (!isSubsetOfLanes(suspendedLanes, lanes)) {451 // We should prefer to render the fallback of at the last452 // suspended level. Ping the last suspended level to try453 // rendering it again.454 // FIXME: What if the suspended lanes are Idle? Should not restart.455 var eventTime = requestEventTime();456 markRootPinged(root, suspendedLanes);457 break;458 } // The render is suspended, it hasn't timed out, and there's no459 // lower priority work to do. Instead of committing the fallback460 // immediately, wait for more data to arrive.461 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), msUntilTimeout);462 break;463 }464 } // The work expired. Commit immediately.465 commitRoot(root);466 break;467 }468 case RootSuspendedWithDelay:469 {470 markRootSuspended$1(root, lanes);471 if (includesOnlyTransitions(lanes)) {472 // This is a transition, so we should exit without committing a473 // placeholder and without scheduling a timeout. Delay indefinitely474 // until we receive more data.475 break;476 }477 if (!shouldForceFlushFallbacksInDEV()) {478 // This is not a transition, but we did trigger an avoided state.479 // Schedule a placeholder to display after a short delay, using the Just480 // Noticeable Difference.481 // TODO: Is the JND optimization worth the added complexity? If this is482 // the only reason we track the event time, then probably not.483 // Consider removing.484 var mostRecentEventTime = getMostRecentEventTime(root, lanes);485 var eventTimeMs = mostRecentEventTime;486 var timeElapsedMs = now() - eventTimeMs;487 var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time.488 if (_msUntilTimeout > 10) {489 // Instead of committing the fallback immediately, wait for more data490 // to arrive.491 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout);492 break;493 }494 } // Commit the placeholder.495 commitRoot(root);496 break;497 }498 case RootCompleted:499 {500 // The work completed. Ready to commit.501 commitRoot(root);502 break;503 }504 default:505 {506 {507 {508 throw Error( "Unknown root exit status." );509 }510 }511 }512 }513 }514 function markRootSuspended$1(root, suspendedLanes) {515 // When suspending, we should always exclude lanes that were pinged or (more516 // rarely, since we try to avoid it) updated during the render phase.517 // TODO: Lol maybe there's a better way to factor this besides this518 // obnoxiously named function :)519 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);520 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);521 markRootSuspended(root, suspendedLanes);522 } // This is the entry point for synchronous tasks that don't go523 // through Scheduler524 function performSyncWorkOnRoot(root) {525 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {526 {527 throw Error( "Should not already be working." );528 }529 }530 flushPassiveEffects();531 var lanes;532 var exitStatus;533 if (root === workInProgressRoot && includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)) {534 // There's a partial tree, and at least one of its lanes has expired. Finish535 // rendering it before rendering the rest of the expired work.536 lanes = workInProgressRootRenderLanes;537 exitStatus = renderRootSync(root, lanes);538 if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {539 // The render included lanes that were updated during the render phase.540 // For example, when unhiding a hidden tree, we include all the lanes541 // that were previously skipped when the tree was hidden. That set of542 // lanes is a superset of the lanes we started rendering with.543 //544 // Note that this only happens when part of the tree is rendered545 // concurrently. If the whole tree is rendered synchronously, then there546 // are no interleaved events.547 lanes = getNextLanes(root, lanes);548 exitStatus = renderRootSync(root, lanes);549 }550 } else {551 lanes = getNextLanes(root, NoLanes);552 exitStatus = renderRootSync(root, lanes);553 }554 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {555 executionContext |= RetryAfterError; // If an error occurred during hydration,556 // discard server response and fall back to client side render.557 if (root.hydrate) {558 root.hydrate = false;559 clearContainer(root.containerInfo);560 } // If something threw an error, try rendering one more time. We'll render561 // synchronously to block concurrent data mutations, and we'll includes562 // all pending updates are included. If it still fails after the second563 // attempt, we'll give up and commit the resulting tree.564 lanes = getLanesToRetrySynchronouslyOnError(root);565 if (lanes !== NoLanes) {566 exitStatus = renderRootSync(root, lanes);567 }568 }569 if (exitStatus === RootFatalErrored) {570 var fatalError = workInProgressRootFatalError;571 prepareFreshStack(root, NoLanes);572 markRootSuspended$1(root, lanes);573 ensureRootIsScheduled(root, now());574 throw fatalError;575 } // We now have a consistent tree. Because this is a sync render, we576 // will commit it even if something suspended.577 var finishedWork = root.current.alternate;578 root.finishedWork = finishedWork;579 root.finishedLanes = lanes;580 commitRoot(root); // Before exiting, make sure there's a callback scheduled for the next581 // pending level.582 ensureRootIsScheduled(root, now());583 return null;584 }585 function flushRoot(root, lanes) {586 markRootExpired(root, lanes);587 ensureRootIsScheduled(root, now());588 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {589 resetRenderTimer();590 flushSyncCallbackQueue();591 }592 }593 function getExecutionContext() {594 return executionContext;595 }596 // flush reactäºä»¶597 function flushDiscreteUpdates() {598 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.599 // However, `act` uses `batchedUpdates`, so there's no way to distinguish600 // those two cases. Need to fix this before exposing flushDiscreteUpdates601 // as a public API.602 if ((executionContext & (BatchedContext | RenderContext | CommitContext)) !== NoContext) {603 {604 if ((executionContext & RenderContext) !== NoContext) {605 error('unstable_flushDiscreteUpdates: Cannot flush updates when React is ' + 'already rendering.');606 }607 } // We're already rendering, so we can't synchronously flush pending work.608 // This is probably a nested event dispatch triggered by a lifecycle/effect,609 // like `el.focus()`. Exit.610 return;611 }612 flushPendingDiscreteUpdates(); // If the discrete updates scheduled passive effects, flush them now so that613 // they fire before the next serial event.614 flushPassiveEffects();615 }616 function flushPendingDiscreteUpdates() {617 if (rootsWithPendingDiscreteUpdates !== null) {618 // For each root with pending discrete updates, schedule a callback to619 // immediately flush them.620 var roots = rootsWithPendingDiscreteUpdates;621 rootsWithPendingDiscreteUpdates = null;622 roots.forEach(function (root) {623 markDiscreteUpdatesExpired(root);624 ensureRootIsScheduled(root, now());625 });626 } // Now flush the immediate queue.627 flushSyncCallbackQueue();628 }629 function batchedUpdates$1(fn, a) {630 var prevExecutionContext = executionContext;631 executionContext |= BatchedContext;632 try {633 return fn(a);634 } finally {635 executionContext = prevExecutionContext;636 if (executionContext === NoContext) {637 // Flush the immediate callbacks that were scheduled during this batch638 resetRenderTimer();639 flushSyncCallbackQueue();640 }641 }642 }643 function batchedEventUpdates$1(fn, a) {644 var prevExecutionContext = executionContext;645 executionContext |= EventContext;646 try {647 return fn(a);648 } finally {649 executionContext = prevExecutionContext;650 if (executionContext === NoContext) {651 // Flush the immediate callbacks that were scheduled during this batch652 resetRenderTimer();653 flushSyncCallbackQueue();654 }655 }656 }657 function discreteUpdates$1(fn, a, b, c, d) {658 var prevExecutionContext = executionContext;659 executionContext |= DiscreteEventContext;660 {661 try {662 return runWithPriority$1(UserBlockingPriority$2, fn.bind(null, a, b, c, d));663 } finally {664 executionContext = prevExecutionContext;665 if (executionContext === NoContext) {666 // Flush the immediate callbacks that were scheduled during this batch667 resetRenderTimer();668 flushSyncCallbackQueue();669 }670 }671 }672 }673 // éæ¹éæ´æ°674 function unbatchedUpdates(fn, a) {675 var prevExecutionContext = executionContext;676 executionContext &= ~BatchedContext;677 executionContext |= LegacyUnbatchedContext;678 try {679 return fn(a);680 } finally {681 executionContext = prevExecutionContext;682 if (executionContext === NoContext) {683 // Flush the immediate callbacks that were scheduled during this batch684 resetRenderTimer();685 flushSyncCallbackQueue();686 }687 }688 }689 function flushSync(fn, a) {690 var prevExecutionContext = executionContext;691 if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {692 {693 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.');694 }695 return fn(a);696 }697 executionContext |= BatchedContext;698 {699 try {700 if (fn) {701 return runWithPriority$1(ImmediatePriority$1, fn.bind(null, a));702 } else {703 return undefined;704 }705 } finally {706 executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch.707 // Note that this will happen even if batchedUpdates is higher up708 // the stack.709 flushSyncCallbackQueue();710 }711 }712 }713 function flushControlled(fn) {714 var prevExecutionContext = executionContext;715 executionContext |= BatchedContext;716 {717 try {718 runWithPriority$1(ImmediatePriority$1, fn);719 } finally {720 executionContext = prevExecutionContext;721 if (executionContext === NoContext) {722 // Flush the immediate callbacks that were scheduled during this batch723 resetRenderTimer();724 flushSyncCallbackQueue();725 }726 }727 }728 }729 function pushRenderLanes(fiber, lanes) {730 push(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);731 subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);732 workInProgressRootIncludedLanes = mergeLanes(workInProgressRootIncludedLanes, lanes);733 }734 function popRenderLanes(fiber) {735 subtreeRenderLanes = subtreeRenderLanesCursor.current;736 pop(subtreeRenderLanesCursor, fiber);737 }738 function prepareFreshStack(root, lanes) {739 root.finishedWork = null;740 root.finishedLanes = NoLanes;741 var timeoutHandle = root.timeoutHandle;742 if (timeoutHandle !== noTimeout) {743 // The root previous suspended and scheduled a timeout to commit a fallback744 // state. Now that we have additional work, cancel the timeout.745 root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above746 cancelTimeout(timeoutHandle);747 }748 if (workInProgress !== null) {749 var interruptedWork = workInProgress.return;750 while (interruptedWork !== null) {751 unwindInterruptedWork(interruptedWork);752 interruptedWork = interruptedWork.return;753 }754 }755 workInProgressRoot = root;756 workInProgress = createWorkInProgress(root.current, null);757 workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;758 workInProgressRootExitStatus = RootIncomplete;759 workInProgressRootFatalError = null;760 workInProgressRootSkippedLanes = NoLanes;761 workInProgressRootUpdatedLanes = NoLanes;762 workInProgressRootPingedLanes = NoLanes;763 {764 spawnedWorkDuringRender = null;765 }766 {767 ReactStrictModeWarnings.discardPendingWarnings();768 }769 }770 function handleError(root, thrownValue) {771 do {772 var erroredWork = workInProgress;773 try {774 // Reset module-level state that was set during the render phase.775 resetContextDependencies();776 resetHooksAfterThrow();777 resetCurrentFiber(); // TODO: I found and added this missing line while investigating a778 // separate issue. Write a regression test using string refs.779 ReactCurrentOwner$2.current = null;780 if (erroredWork === null || erroredWork.return === null) {781 // Expected to be working on a non-root fiber. This is a fatal error782 // because there's no ancestor that can handle it; the root is783 // supposed to capture all errors that weren't caught by an error784 // boundary.785 workInProgressRootExitStatus = RootFatalErrored;786 workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next787 // sibling, or the parent if there are no siblings. But since the root788 // has no siblings nor a parent, we set it to null. Usually this is789 // handled by `completeUnitOfWork` or `unwindWork`, but since we're790 // intentionally not calling those, we need set it here.791 // TODO: Consider calling `unwindWork` to pop the contexts.792 workInProgress = null;793 return;794 }795 if (enableProfilerTimer && erroredWork.mode & ProfileMode) {796 // Record the time spent rendering before an error was thrown. This797 // avoids inaccurate Profiler durations in the case of a798 // suspended render.799 stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);800 }801 throwException(root, erroredWork.return, erroredWork, thrownValue, workInProgressRootRenderLanes);802 completeUnitOfWork(erroredWork);803 } catch (yetAnotherThrownValue) {804 // Something in the return path also threw.805 thrownValue = yetAnotherThrownValue;806 if (workInProgress === erroredWork && erroredWork !== null) {807 // If this boundary has already errored, then we had trouble processing808 // the error. Bubble it to the next boundary.809 erroredWork = erroredWork.return;810 workInProgress = erroredWork;811 } else {812 erroredWork = workInProgress;813 }814 continue;815 } // Return to the normal work loop.816 return;817 } while (true);818 }819 function pushDispatcher() {820 var prevDispatcher = ReactCurrentDispatcher$2.current;821 ReactCurrentDispatcher$2.current = ContextOnlyDispatcher;822 if (prevDispatcher === null) {823 // The React isomorphic package does not include a default dispatcher.824 // Instead the first renderer will lazily attach one, in order to give825 // nicer error messages.826 return ContextOnlyDispatcher;827 } else {828 return prevDispatcher;829 }830 }831 function popDispatcher(prevDispatcher) {832 ReactCurrentDispatcher$2.current = prevDispatcher;833 }834 function pushInteractions(root) {835 {836 var prevInteractions = __interactionsRef.current;837 __interactionsRef.current = root.memoizedInteractions;838 return prevInteractions;839 }840 }841 function popInteractions(prevInteractions) {842 {843 __interactionsRef.current = prevInteractions;844 }845 }846 function markCommitTimeOfFallback() {847 globalMostRecentFallbackTime = now();848 }849 function markSkippedUpdateLanes(lane) {850 workInProgressRootSkippedLanes = mergeLanes(lane, workInProgressRootSkippedLanes);851 }852 function renderDidSuspend() {853 if (workInProgressRootExitStatus === RootIncomplete) {854 workInProgressRootExitStatus = RootSuspended;855 }856 }857 function renderDidSuspendDelayIfPossible() {858 if (workInProgressRootExitStatus === RootIncomplete || workInProgressRootExitStatus === RootSuspended) {859 workInProgressRootExitStatus = RootSuspendedWithDelay;860 } // Check if there are updates that we skipped tree that might have unblocked861 // this render.862 if (workInProgressRoot !== null && (includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootUpdatedLanes))) {863 // Mark the current render as suspended so that we switch to working on864 // the updates that were skipped. Usually we only suspend at the end of865 // the render phase.866 // TODO: We should probably always mark the root as suspended immediately867 // (inside this function), since by suspending at the end of the render868 // phase introduces a potential mistake where we suspend lanes that were869 // pinged or updated while we were rendering.870 markRootSuspended$1(workInProgressRoot, workInProgressRootRenderLanes);871 }872 }873 function renderDidError() {874 if (workInProgressRootExitStatus !== RootCompleted) {875 workInProgressRootExitStatus = RootErrored;876 }877 } // Called during render to determine if anything has suspended.878 // Returns false if we're not sure.879 function renderHasNotSuspendedYet() {880 // If something errored or completed, we can't really be sure,881 // so those are false.882 return workInProgressRootExitStatus === RootIncomplete;883 }884 function renderRootSync(root, lanes) {885 var prevExecutionContext = executionContext;886 executionContext |= RenderContext;887 var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack888 // and prepare a fresh one. Otherwise we'll continue where we left off.889 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {890 prepareFreshStack(root, lanes);891 startWorkOnPendingInteractions(root, lanes);892 }893 var prevInteractions = pushInteractions(root);894 {895 markRenderStarted(lanes);896 }897 do {898 try {899 workLoopSync();900 break;901 } catch (thrownValue) {902 handleError(root, thrownValue);903 }904 } while (true);905 resetContextDependencies();906 {907 popInteractions(prevInteractions);908 }909 executionContext = prevExecutionContext;910 popDispatcher(prevDispatcher);911 if (workInProgress !== null) {912 // This is a sync render, so we should have finished the whole tree.913 {914 {915 throw Error( "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." );916 }917 }918 }919 {920 markRenderStopped();921 } // Set this to null to indicate there's no in-progress render.922 workInProgressRoot = null;923 workInProgressRootRenderLanes = NoLanes;924 return workInProgressRootExitStatus;925 } // The work loop is an extremely hot path. Tell Closure not to inline it.926 /** @noinline */927 function workLoopSync() {928 // Already timed out, so perform work without checking if we need to yield.929 while (workInProgress !== null) {930 performUnitOfWork(workInProgress);931 }932 }933 function renderRootConcurrent(root, lanes) {934 var prevExecutionContext = executionContext;935 executionContext |= RenderContext;936 var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack937 // and prepare a fresh one. Otherwise we'll continue where we left off.938 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {939 resetRenderTimer();940 prepareFreshStack(root, lanes);941 startWorkOnPendingInteractions(root, lanes);942 }943 var prevInteractions = pushInteractions(root);944 {945 markRenderStarted(lanes);946 }947 do {948 try {949 workLoopConcurrent();950 break;951 } catch (thrownValue) {952 handleError(root, thrownValue);953 }954 } while (true);955 resetContextDependencies();956 {957 popInteractions(prevInteractions);958 }959 popDispatcher(prevDispatcher);960 executionContext = prevExecutionContext;961 if (workInProgress !== null) {962 // Still work remaining.963 {964 markRenderYielded();965 }966 return RootIncomplete;967 } else {968 // Completed the tree.969 {970 markRenderStopped();971 } // Set this to null to indicate there's no in-progress render.972 workInProgressRoot = null;973 workInProgressRootRenderLanes = NoLanes; // Return the final exit status.974 return workInProgressRootExitStatus;975 }976 }977 /** @noinline */978 function workLoopConcurrent() {979 // Perform work until Scheduler asks us to yield980 while (workInProgress !== null && !shouldYield()) {981 performUnitOfWork(workInProgress);982 }983 }984 function performUnitOfWork(unitOfWork) {985 // The current, flushed, state of this fiber is the alternate. Ideally986 // nothing should rely on this, but relying on it here means that we don't987 // need an additional field on the work in progress.988 var current = unitOfWork.alternate;989 setCurrentFiber(unitOfWork);990 var next;991 if ( (unitOfWork.mode & ProfileMode) !== NoMode) {992 startProfilerTimer(unitOfWork);993 next = beginWork$1(current, unitOfWork, subtreeRenderLanes);994 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);995 } else {996 next = beginWork$1(current, unitOfWork, subtreeRenderLanes);997 }998 resetCurrentFiber();999 unitOfWork.memoizedProps = unitOfWork.pendingProps;1000 if (next === null) {1001 // If this doesn't spawn new work, complete the current work.1002 completeUnitOfWork(unitOfWork);1003 } else {1004 workInProgress = next;1005 }1006 ReactCurrentOwner$2.current = null;1007 }1008 function completeUnitOfWork(unitOfWork) {1009 // Attempt to complete the current unit of work, then move to the next1010 // sibling. If there are no more siblings, return to the parent fiber.1011 var completedWork = unitOfWork;1012 do {1013 // The current, flushed, state of this fiber is the alternate. Ideally1014 // nothing should rely on this, but relying on it here means that we don't1015 // need an additional field on the work in progress.1016 var current = completedWork.alternate;1017 var returnFiber = completedWork.return; // Check if the work completed or if something threw.1018 if ((completedWork.flags & Incomplete) === NoFlags) {1019 setCurrentFiber(completedWork);1020 var next = void 0;1021 if ( (completedWork.mode & ProfileMode) === NoMode) {1022 next = completeWork(current, completedWork, subtreeRenderLanes);1023 } else {1024 startProfilerTimer(completedWork);1025 next = completeWork(current, completedWork, subtreeRenderLanes); // Update render duration assuming we didn't error.1026 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1027 }1028 resetCurrentFiber();1029 if (next !== null) {1030 // Completing this fiber spawned new work. Work on that next.1031 workInProgress = next;1032 return;1033 }1034 resetChildLanes(completedWork);1035 if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete1036 (returnFiber.flags & Incomplete) === NoFlags) {1037 // Append all the effects of the subtree and this fiber onto the effect1038 // list of the parent. The completion order of the children affects the1039 // side-effect order.1040 if (returnFiber.firstEffect === null) {1041 returnFiber.firstEffect = completedWork.firstEffect;1042 }1043 if (completedWork.lastEffect !== null) {1044 if (returnFiber.lastEffect !== null) {1045 returnFiber.lastEffect.nextEffect = completedWork.firstEffect;1046 }1047 returnFiber.lastEffect = completedWork.lastEffect;1048 } // If this fiber had side-effects, we append it AFTER the children's1049 // side-effects. We can perform certain side-effects earlier if needed,1050 // by doing multiple passes over the effect list. We don't want to1051 // schedule our own side-effect on our own list because if end up1052 // reusing children we'll schedule this effect onto itself since we're1053 // at the end.1054 var flags = completedWork.flags; // Skip both NoWork and PerformedWork tags when creating the effect1055 // list. PerformedWork effect is read by React DevTools but shouldn't be1056 // committed.1057 if (flags > PerformedWork) {1058 if (returnFiber.lastEffect !== null) {1059 returnFiber.lastEffect.nextEffect = completedWork;1060 } else {1061 returnFiber.firstEffect = completedWork;1062 }1063 returnFiber.lastEffect = completedWork;1064 }1065 }1066 } else {1067 // This fiber did not complete because something threw. Pop values off1068 // the stack without entering the complete phase. If this is a boundary,1069 // capture values if possible.1070 var _next = unwindWork(completedWork); // Because this fiber did not complete, don't reset its expiration time.1071 if (_next !== null) {1072 // If completing this work spawned new work, do that next. We'll come1073 // back here again.1074 // Since we're restarting, remove anything that is not a host effect1075 // from the effect tag.1076 _next.flags &= HostEffectMask;1077 workInProgress = _next;1078 return;1079 }1080 if ( (completedWork.mode & ProfileMode) !== NoMode) {1081 // Record the render duration for the fiber that errored.1082 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.1083 var actualDuration = completedWork.actualDuration;1084 var child = completedWork.child;1085 while (child !== null) {1086 actualDuration += child.actualDuration;1087 child = child.sibling;1088 }1089 completedWork.actualDuration = actualDuration;1090 }1091 if (returnFiber !== null) {1092 // Mark the parent fiber as incomplete and clear its effect list.1093 returnFiber.firstEffect = returnFiber.lastEffect = null;1094 returnFiber.flags |= Incomplete;1095 }1096 }1097 var siblingFiber = completedWork.sibling;1098 if (siblingFiber !== null) {1099 // If there is more work to do in this returnFiber, do that next.1100 workInProgress = siblingFiber;1101 return;1102 } // Otherwise, return to the parent1103 completedWork = returnFiber; // Update the next thing we're working on in case something throws.1104 workInProgress = completedWork;1105 } while (completedWork !== null); // We've reached the root.1106 if (workInProgressRootExitStatus === RootIncomplete) {1107 workInProgressRootExitStatus = RootCompleted;1108 }1109 }1110 function resetChildLanes(completedWork) {1111 if ( // TODO: Move this check out of the hot path by moving `resetChildLanes`1112 // to switch statement in `completeWork`.1113 (completedWork.tag === LegacyHiddenComponent || completedWork.tag === OffscreenComponent) && completedWork.memoizedState !== null && !includesSomeLane(subtreeRenderLanes, OffscreenLane) && (completedWork.mode & ConcurrentMode) !== NoLanes) {1114 // The children of this component are hidden. Don't bubble their1115 // expiration times.1116 return;1117 }1118 var newChildLanes = NoLanes; // Bubble up the earliest expiration time.1119 if ( (completedWork.mode & ProfileMode) !== NoMode) {1120 // In profiling mode, resetChildExpirationTime is also used to reset1121 // profiler durations.1122 var actualDuration = completedWork.actualDuration;1123 var treeBaseDuration = completedWork.selfBaseDuration; // When a fiber is cloned, its actualDuration is reset to 0. This value will1124 // only be updated if work is done on the fiber (i.e. it doesn't bailout).1125 // When work is done, it should bubble to the parent's actualDuration. If1126 // the fiber has not been cloned though, (meaning no work was done), then1127 // this value will reflect the amount of time spent working on a previous1128 // render. In that case it should not bubble. We determine whether it was1129 // cloned by comparing the child pointer.1130 var shouldBubbleActualDurations = completedWork.alternate === null || completedWork.child !== completedWork.alternate.child;1131 var child = completedWork.child;1132 while (child !== null) {1133 newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));1134 if (shouldBubbleActualDurations) {1135 actualDuration += child.actualDuration;1136 }1137 treeBaseDuration += child.treeBaseDuration;1138 child = child.sibling;1139 }1140 var isTimedOutSuspense = completedWork.tag === SuspenseComponent && completedWork.memoizedState !== null;1141 if (isTimedOutSuspense) {1142 // Don't count time spent in a timed out Suspense subtree as part of the base duration.1143 var primaryChildFragment = completedWork.child;1144 if (primaryChildFragment !== null) {1145 treeBaseDuration -= primaryChildFragment.treeBaseDuration;1146 }1147 }1148 completedWork.actualDuration = actualDuration;1149 completedWork.treeBaseDuration = treeBaseDuration;1150 } else {1151 var _child = completedWork.child;1152 while (_child !== null) {1153 newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));1154 _child = _child.sibling;1155 }1156 }1157 completedWork.childLanes = newChildLanes;1158 }1159 function commitRoot(root) {1160 var renderPriorityLevel = getCurrentPriorityLevel();1161 runWithPriority$1(ImmediatePriority$1, commitRootImpl.bind(null, root, renderPriorityLevel));1162 return null;1163 }1164 function commitRootImpl(root, renderPriorityLevel) {1165 do {1166 // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1167 // means `flushPassiveEffects` will sometimes result in additional1168 // passive effects. So we need to keep flushing in a loop until there are1169 // no more pending effects.1170 // TODO: Might be better if `flushPassiveEffects` did not automatically1171 // flush synchronous work at the end, to avoid factoring hazards like this.1172 flushPassiveEffects();1173 } while (rootWithPendingPassiveEffects !== null);1174 flushRenderPhaseStrictModeWarningsInDEV();1175 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1176 {1177 throw Error( "Should not already be working." );1178 }1179 }1180 var finishedWork = root.finishedWork;1181 var lanes = root.finishedLanes;1182 {1183 markCommitStarted(lanes);1184 }1185 if (finishedWork === null) {1186 {1187 markCommitStopped();1188 }1189 return null;1190 }1191 root.finishedWork = null;1192 root.finishedLanes = NoLanes;1193 if (!(finishedWork !== root.current)) {1194 {1195 throw Error( "Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue." );1196 }1197 } // commitRoot never returns a continuation; it always finishes synchronously.1198 // So we can clear these now to allow a new callback to be scheduled.1199 root.callbackNode = null; // Update the first and last pending times on this root. The new first1200 // pending time is whatever is left on the root fiber.1201 var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);1202 markRootFinished(root, remainingLanes); // Clear already finished discrete updates in case that a later call of1203 // `flushDiscreteUpdates` starts a useless render pass which may cancels1204 // a scheduled timeout.1205 if (rootsWithPendingDiscreteUpdates !== null) {1206 if (!hasDiscreteLanes(remainingLanes) && rootsWithPendingDiscreteUpdates.has(root)) {1207 rootsWithPendingDiscreteUpdates.delete(root);1208 }1209 }1210 if (root === workInProgressRoot) {1211 // We can reset these now that they are finished.1212 workInProgressRoot = null;1213 workInProgress = null;1214 workInProgressRootRenderLanes = NoLanes;1215 } // Get the list of effects.1216 var firstEffect;1217 if (finishedWork.flags > PerformedWork) {1218 // A fiber's effect list consists only of its children, not itself. So if1219 // the root has an effect, we need to add it to the end of the list. The1220 // resulting list is the set that would belong to the root's parent, if it1221 // had one; that is, all the effects in the tree including the root.1222 if (finishedWork.lastEffect !== null) {1223 finishedWork.lastEffect.nextEffect = finishedWork;1224 firstEffect = finishedWork.firstEffect;1225 } else {1226 firstEffect = finishedWork;1227 }1228 } else {1229 // There is no effect on the root.1230 firstEffect = finishedWork.firstEffect;1231 }1232 if (firstEffect !== null) {1233 var prevExecutionContext = executionContext;1234 executionContext |= CommitContext;1235 var prevInteractions = pushInteractions(root); // Reset this to null before calling lifecycles1236 ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass1237 // of the effect list for each phase: all mutation effects come before all1238 // layout effects, and so on.1239 // The first phase a "before mutation" phase. We use this phase to read the1240 // state of the host tree right before we mutate it. This is where1241 // getSnapshotBeforeUpdate is called.1242 focusedInstanceHandle = prepareForCommit(root.containerInfo);1243 shouldFireAfterActiveInstanceBlur = false;1244 nextEffect = firstEffect;1245 do {1246 {1247 invokeGuardedCallback(null, commitBeforeMutationEffects, null);1248 if (hasCaughtError()) {1249 if (!(nextEffect !== null)) {1250 {1251 throw Error( "Should be working on an effect." );1252 }1253 }1254 var error = clearCaughtError();1255 captureCommitPhaseError(nextEffect, error);1256 nextEffect = nextEffect.nextEffect;1257 }1258 }1259 } while (nextEffect !== null); // We no longer need to track the active instance fiber1260 focusedInstanceHandle = null;1261 {1262 // Mark the current commit time to be shared by all Profilers in this1263 // batch. This enables them to be grouped later.1264 recordCommitTime();1265 } // The next phase is the mutation phase, where we mutate the host tree.1266 nextEffect = firstEffect;1267 do {1268 {1269 invokeGuardedCallback(null, commitMutationEffects, null, root, renderPriorityLevel);1270 if (hasCaughtError()) {1271 if (!(nextEffect !== null)) {1272 {1273 throw Error( "Should be working on an effect." );1274 }1275 }1276 var _error = clearCaughtError();1277 captureCommitPhaseError(nextEffect, _error);1278 nextEffect = nextEffect.nextEffect;1279 }1280 }1281 } while (nextEffect !== null);1282 resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after1283 // the mutation phase, so that the previous tree is still current during1284 // componentWillUnmount, but before the layout phase, so that the finished1285 // work is current during componentDidMount/Update.1286 root.current = finishedWork; // The next phase is the layout phase, where we call effects that read1287 // the host tree after it's been mutated. The idiomatic use case for this is1288 // layout, but class component lifecycles also fire here for legacy reasons.1289 nextEffect = firstEffect;1290 do {1291 {1292 invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);1293 if (hasCaughtError()) {1294 if (!(nextEffect !== null)) {1295 {1296 throw Error( "Should be working on an effect." );1297 }1298 }1299 var _error2 = clearCaughtError();1300 captureCommitPhaseError(nextEffect, _error2);1301 nextEffect = nextEffect.nextEffect;1302 }1303 }1304 } while (nextEffect !== null);1305 nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an1306 // opportunity to paint.1307 requestPaint();1308 {1309 popInteractions(prevInteractions);1310 }1311 executionContext = prevExecutionContext;1312 } else {1313 // No effects.1314 root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were1315 // no effects.1316 // TODO: Maybe there's a better way to report this.1317 {1318 recordCommitTime();1319 }1320 }1321 var rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1322 if (rootDoesHavePassiveEffects) {1323 // This commit has passive effects. Stash a reference to them. But don't1324 // schedule a callback until after flushing layout work.1325 rootDoesHavePassiveEffects = false;1326 rootWithPendingPassiveEffects = root;1327 pendingPassiveEffectsLanes = lanes;1328 pendingPassiveEffectsRenderPriority = renderPriorityLevel;1329 } else {1330 // We are done with the effect chain at this point so let's clear the1331 // nextEffect pointers to assist with GC. If we have passive effects, we'll1332 // clear this in flushPassiveEffects.1333 nextEffect = firstEffect;1334 while (nextEffect !== null) {1335 var nextNextEffect = nextEffect.nextEffect;1336 nextEffect.nextEffect = null;1337 if (nextEffect.flags & Deletion) {1338 detachFiberAfterEffects(nextEffect);1339 }1340 nextEffect = nextNextEffect;1341 }1342 } // Read this again, since an effect might have updated it1343 remainingLanes = root.pendingLanes; // Check if there's remaining work on this root1344 if (remainingLanes !== NoLanes) {1345 {1346 if (spawnedWorkDuringRender !== null) {1347 var expirationTimes = spawnedWorkDuringRender;1348 spawnedWorkDuringRender = null;1349 for (var i = 0; i < expirationTimes.length; i++) {1350 scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions);1351 }1352 }1353 schedulePendingInteractions(root, remainingLanes);1354 }1355 } else {1356 // If there's no remaining work, we can clear the set of already failed1357 // error boundaries.1358 legacyErrorBoundariesThatAlreadyFailed = null;1359 }1360 {1361 if (!rootDidHavePassiveEffects) {1362 // If there are no passive effects, then we can complete the pending interactions.1363 // Otherwise, we'll wait until after the passive effects are flushed.1364 // Wait to do this until after remaining work has been scheduled,1365 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1366 finishPendingInteractions(root, lanes);1367 }1368 }1369 if (remainingLanes === SyncLane) {1370 // Count the number of times the root synchronously re-renders without1371 // finishing. If there are too many, it indicates an infinite update loop.1372 if (root === rootWithNestedUpdates) {1373 nestedUpdateCount++;1374 } else {1375 nestedUpdateCount = 0;1376 rootWithNestedUpdates = root;1377 }1378 } else {1379 nestedUpdateCount = 0;1380 }1381 onCommitRoot(finishedWork.stateNode, renderPriorityLevel);1382 {1383 onCommitRoot$1();1384 } // Always call this before exiting `commitRoot`, to ensure that any1385 // additional work on this root is scheduled.1386 ensureRootIsScheduled(root, now());1387 if (hasUncaughtError) {1388 hasUncaughtError = false;1389 var _error3 = firstUncaughtError;1390 firstUncaughtError = null;1391 throw _error3;1392 }1393 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1394 {1395 markCommitStopped();1396 } // This is a legacy edge case. We just committed the initial mount of1397 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1398 // synchronously, but layout updates should be deferred until the end1399 // of the batch.1400 return null;1401 } // If layout work was scheduled, flush it now.1402 flushSyncCallbackQueue();1403 {1404 markCommitStopped();1405 }1406 return null;1407 }1408 function commitBeforeMutationEffects() {1409 while (nextEffect !== null) {1410 var current = nextEffect.alternate;1411 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1412 if ((nextEffect.flags & Deletion) !== NoFlags) {1413 if (doesFiberContain(nextEffect, focusedInstanceHandle)) {1414 shouldFireAfterActiveInstanceBlur = true;1415 }1416 } else {1417 // TODO: Move this out of the hot path using a dedicated effect tag.1418 if (nextEffect.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, nextEffect) && doesFiberContain(nextEffect, focusedInstanceHandle)) {1419 shouldFireAfterActiveInstanceBlur = true;1420 }1421 }1422 }1423 var flags = nextEffect.flags;1424 if ((flags & Snapshot) !== NoFlags) {1425 setCurrentFiber(nextEffect);1426 commitBeforeMutationLifeCycles(current, nextEffect);1427 resetCurrentFiber();1428 }1429 if ((flags & Passive) !== NoFlags) {1430 // If there are passive effects, schedule a callback to flush at1431 // the earliest opportunity.1432 if (!rootDoesHavePassiveEffects) {1433 rootDoesHavePassiveEffects = true;1434 scheduleCallback(NormalPriority$1, function () {1435 flushPassiveEffects();1436 return null;1437 });1438 }1439 }1440 nextEffect = nextEffect.nextEffect;1441 }1442 }1443 function commitMutationEffects(root, renderPriorityLevel) {1444 // TODO: Should probably move the bulk of this function to commitWork.1445 while (nextEffect !== null) {1446 setCurrentFiber(nextEffect);1447 var flags = nextEffect.flags;1448 if (flags & ContentReset) {1449 commitResetTextContent(nextEffect);1450 }1451 if (flags & Ref) {1452 var current = nextEffect.alternate;1453 if (current !== null) {1454 commitDetachRef(current);1455 }1456 } // The following switch statement is only concerned about placement,1457 // updates, and deletions. To avoid needing to add a case for every possible1458 // bitmap value, we remove the secondary effects from the effect tag and1459 // switch on that value.1460 var primaryFlags = flags & (Placement | Update | Deletion | Hydrating);1461 switch (primaryFlags) {1462 case Placement:1463 {1464 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1465 // inserted, before any life-cycles like componentDidMount gets called.1466 // TODO: findDOMNode doesn't rely on this any more but isMounted does1467 // and isMounted is deprecated anyway so we should be able to kill this.1468 nextEffect.flags &= ~Placement;1469 break;1470 }1471 case PlacementAndUpdate:1472 {1473 // Placement1474 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1475 // inserted, before any life-cycles like componentDidMount gets called.1476 nextEffect.flags &= ~Placement; // Update1477 var _current = nextEffect.alternate;1478 commitWork(_current, nextEffect);1479 break;1480 }1481 case Hydrating:1482 {1483 nextEffect.flags &= ~Hydrating;1484 break;1485 }1486 case HydratingAndUpdate:1487 {1488 nextEffect.flags &= ~Hydrating; // Update1489 var _current2 = nextEffect.alternate;1490 commitWork(_current2, nextEffect);1491 break;1492 }1493 case Update:1494 {1495 var _current3 = nextEffect.alternate;1496 commitWork(_current3, nextEffect);1497 break;1498 }1499 case Deletion:1500 {1501 commitDeletion(root, nextEffect);1502 break;1503 }1504 }1505 resetCurrentFiber();1506 nextEffect = nextEffect.nextEffect;1507 }1508 }1509 function commitLayoutEffects(root, committedLanes) {1510 {1511 markLayoutEffectsStarted(committedLanes);1512 } // TODO: Should probably move the bulk of this function to commitWork.1513 while (nextEffect !== null) {1514 setCurrentFiber(nextEffect);1515 var flags = nextEffect.flags;1516 if (flags & (Update | Callback)) {1517 var current = nextEffect.alternate;1518 commitLifeCycles(root, current, nextEffect);1519 }1520 {1521 if (flags & Ref) {1522 commitAttachRef(nextEffect);1523 }1524 }1525 resetCurrentFiber();1526 nextEffect = nextEffect.nextEffect;1527 }1528 {1529 markLayoutEffectsStopped();1530 }1531 }1532 function flushPassiveEffects() {1533 // Returns whether passive effects were flushed.1534 if (pendingPassiveEffectsRenderPriority !== NoPriority$1) {1535 var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority$1 ? NormalPriority$1 : pendingPassiveEffectsRenderPriority;1536 pendingPassiveEffectsRenderPriority = NoPriority$1;1537 {1538 return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl);1539 }1540 }1541 return false;1542 }1543 function enqueuePendingPassiveHookEffectMount(fiber, effect) {1544 pendingPassiveHookEffectsMount.push(effect, fiber);1545 if (!rootDoesHavePassiveEffects) {1546 rootDoesHavePassiveEffects = true;1547 scheduleCallback(NormalPriority$1, function () {1548 flushPassiveEffects();1549 return null;1550 });1551 }1552 }1553 function enqueuePendingPassiveHookEffectUnmount(fiber, effect) {1554 pendingPassiveHookEffectsUnmount.push(effect, fiber);1555 {1556 fiber.flags |= PassiveUnmountPendingDev;1557 var alternate = fiber.alternate;1558 if (alternate !== null) {1559 alternate.flags |= PassiveUnmountPendingDev;1560 }1561 }1562 if (!rootDoesHavePassiveEffects) {1563 rootDoesHavePassiveEffects = true;1564 scheduleCallback(NormalPriority$1, function () {1565 flushPassiveEffects();1566 return null;1567 });1568 }1569 }1570 function invokePassiveEffectCreate(effect) {1571 var create = effect.create;1572 effect.destroy = create();1573 }1574 function flushPassiveEffectsImpl() {1575 if (rootWithPendingPassiveEffects === null) {1576 return false;1577 }1578 var root = rootWithPendingPassiveEffects;1579 var lanes = pendingPassiveEffectsLanes;1580 rootWithPendingPassiveEffects = null;1581 pendingPassiveEffectsLanes = NoLanes;1582 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1583 {1584 throw Error( "Cannot flush passive effects while already rendering." );1585 }1586 }1587 {1588 markPassiveEffectsStarted(lanes);1589 }1590 {1591 isFlushingPassiveEffects = true;1592 }1593 var prevExecutionContext = executionContext;1594 executionContext |= CommitContext;1595 var prevInteractions = pushInteractions(root); // It's important that ALL pending passive effect destroy functions are called1596 // before ANY passive effect create functions are called.1597 // Otherwise effects in sibling components might interfere with each other.1598 // e.g. a destroy function in one component may unintentionally override a ref1599 // value set by a create function in another component.1600 // Layout effects have the same constraint.1601 // First pass: Destroy stale passive effects.1602 var unmountEffects = pendingPassiveHookEffectsUnmount;1603 pendingPassiveHookEffectsUnmount = [];1604 for (var i = 0; i < unmountEffects.length; i += 2) {1605 var _effect = unmountEffects[i];1606 var fiber = unmountEffects[i + 1];1607 var destroy = _effect.destroy;1608 _effect.destroy = undefined;1609 {1610 fiber.flags &= ~PassiveUnmountPendingDev;1611 var alternate = fiber.alternate;1612 if (alternate !== null) {1613 alternate.flags &= ~PassiveUnmountPendingDev;1614 }1615 }1616 if (typeof destroy === 'function') {1617 {1618 setCurrentFiber(fiber);1619 {1620 invokeGuardedCallback(null, destroy, null);1621 }1622 if (hasCaughtError()) {1623 if (!(fiber !== null)) {1624 {1625 throw Error( "Should be working on an effect." );1626 }1627 }1628 var error = clearCaughtError();1629 captureCommitPhaseError(fiber, error);1630 }1631 resetCurrentFiber();1632 }1633 }1634 } // Second pass: Create new passive effects.1635 var mountEffects = pendingPassiveHookEffectsMount;1636 pendingPassiveHookEffectsMount = [];1637 for (var _i = 0; _i < mountEffects.length; _i += 2) {1638 var _effect2 = mountEffects[_i];1639 var _fiber = mountEffects[_i + 1];1640 {1641 setCurrentFiber(_fiber);1642 {1643 invokeGuardedCallback(null, invokePassiveEffectCreate, null, _effect2);1644 }1645 if (hasCaughtError()) {1646 if (!(_fiber !== null)) {1647 {1648 throw Error( "Should be working on an effect." );1649 }1650 }1651 var _error4 = clearCaughtError();1652 captureCommitPhaseError(_fiber, _error4);1653 }1654 resetCurrentFiber();1655 }1656 } // Note: This currently assumes there are no passive effects on the root fiber1657 // because the root is not part of its own effect list.1658 // This could change in the future.1659 var effect = root.current.firstEffect;1660 while (effect !== null) {1661 var nextNextEffect = effect.nextEffect; // Remove nextEffect pointer to assist GC1662 effect.nextEffect = null;1663 if (effect.flags & Deletion) {1664 detachFiberAfterEffects(effect);1665 }1666 effect = nextNextEffect;1667 }1668 {1669 popInteractions(prevInteractions);1670 finishPendingInteractions(root, lanes);1671 }1672 {1673 isFlushingPassiveEffects = false;1674 }1675 {1676 markPassiveEffectsStopped();1677 }1678 executionContext = prevExecutionContext;1679 flushSyncCallbackQueue(); // If additional passive effects were scheduled, increment a counter. If this1680 // exceeds the limit, we'll fire a warning.1681 nestedPassiveUpdateCount = rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;1682 return true;1683 }1684 function isAlreadyFailedLegacyErrorBoundary(instance) {1685 return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance);1686 }1687 function markLegacyErrorBoundaryAsFailed(instance) {1688 if (legacyErrorBoundariesThatAlreadyFailed === null) {1689 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);1690 } else {1691 legacyErrorBoundariesThatAlreadyFailed.add(instance);1692 }1693 }1694 function prepareToThrowUncaughtError(error) {1695 if (!hasUncaughtError) {1696 hasUncaughtError = true;1697 firstUncaughtError = error;1698 }1699 }1700 var onUncaughtError = prepareToThrowUncaughtError;1701 function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) {1702 var errorInfo = createCapturedValue(error, sourceFiber);1703 var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane);1704 enqueueUpdate(rootFiber, update);1705 var eventTime = requestEventTime();1706 var root = markUpdateLaneFromFiberToRoot(rootFiber, SyncLane);1707 if (root !== null) {1708 markRootUpdated(root, SyncLane, eventTime);1709 ensureRootIsScheduled(root, eventTime);1710 schedulePendingInteractions(root, SyncLane);1711 }1712 }1713 function captureCommitPhaseError(sourceFiber, error) {1714 if (sourceFiber.tag === HostRoot) {1715 // Error was thrown at the root. There is no parent, so the root1716 // itself should capture it.1717 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);1718 return;1719 }1720 var fiber = sourceFiber.return;1721 while (fiber !== null) {1722 if (fiber.tag === HostRoot) {1723 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);1724 return;1725 } else if (fiber.tag === ClassComponent) {1726 var ctor = fiber.type;1727 var instance = fiber.stateNode;1728 if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {1729 var errorInfo = createCapturedValue(error, sourceFiber);1730 var update = createClassErrorUpdate(fiber, errorInfo, SyncLane);1731 enqueueUpdate(fiber, update);1732 var eventTime = requestEventTime();1733 var root = markUpdateLaneFromFiberToRoot(fiber, SyncLane);1734 if (root !== null) {1735 markRootUpdated(root, SyncLane, eventTime);1736 ensureRootIsScheduled(root, eventTime);1737 schedulePendingInteractions(root, SyncLane);1738 } else {1739 // This component has already been unmounted.1740 // We can't schedule any follow up work for the root because the fiber is already unmounted,1741 // but we can still call the log-only boundary so the error isn't swallowed.1742 //1743 // TODO This is only a temporary bandaid for the old reconciler fork.1744 // We can delete this special case once the new fork is merged.1745 if (typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {1746 try {1747 instance.componentDidCatch(error, errorInfo);1748 } catch (errorToIgnore) {// TODO Ignore this error? Rethrow it?1749 // This is kind of an edge case.1750 }1751 }1752 }1753 return;1754 }1755 }1756 fiber = fiber.return;1757 }1758 }1759 function pingSuspendedRoot(root, wakeable, pingedLanes) {1760 var pingCache = root.pingCache;1761 if (pingCache !== null) {1762 // The wakeable resolved, so we no longer need to memoize, because it will1763 // never be thrown again.1764 pingCache.delete(wakeable);1765 }1766 var eventTime = requestEventTime();1767 markRootPinged(root, pingedLanes);1768 if (workInProgressRoot === root && isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)) {1769 // Received a ping at the same priority level at which we're currently1770 // rendering. We might want to restart this render. This should mirror1771 // the logic of whether or not a root suspends once it completes.1772 // TODO: If we're rendering sync either due to Sync, Batched or expired,1773 // we should probably never restart.1774 // If we're suspended with delay, or if it's a retry, we'll always suspend1775 // so we can always restart.1776 if (workInProgressRootExitStatus === RootSuspendedWithDelay || workInProgressRootExitStatus === RootSuspended && includesOnlyRetries(workInProgressRootRenderLanes) && now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) {1777 // Restart from the root.1778 prepareFreshStack(root, NoLanes);1779 } else {1780 // Even though we can't restart right now, we might get an1781 // opportunity later. So we mark this render as having a ping.1782 workInProgressRootPingedLanes = mergeLanes(workInProgressRootPingedLanes, pingedLanes);1783 }1784 }1785 ensureRootIsScheduled(root, eventTime);1786 schedulePendingInteractions(root, pingedLanes);1787 }1788 function retryTimedOutBoundary(boundaryFiber, retryLane) {1789 // The boundary fiber (a Suspense component or SuspenseList component)1790 // previously was rendered in its fallback state. One of the promises that1791 // suspended it has resolved, which means at least part of the tree was1792 // likely unblocked. Try rendering again, at a new expiration time.1793 if (retryLane === NoLane) {1794 retryLane = requestRetryLane(boundaryFiber);1795 } // TODO: Special case idle priority?1796 var eventTime = requestEventTime();1797 var root = markUpdateLaneFromFiberToRoot(boundaryFiber, retryLane);1798 if (root !== null) {1799 markRootUpdated(root, retryLane, eventTime);1800 ensureRootIsScheduled(root, eventTime);1801 schedulePendingInteractions(root, retryLane);1802 }1803 }1804 function retryDehydratedSuspenseBoundary(boundaryFiber) {1805 var suspenseState = boundaryFiber.memoizedState;1806 var retryLane = NoLane;1807 if (suspenseState !== null) {1808 retryLane = suspenseState.retryLane;1809 }1810 retryTimedOutBoundary(boundaryFiber, retryLane);1811 }1812 function resolveRetryWakeable(boundaryFiber, wakeable) {1813 var retryLane = NoLane; // Default1814 var retryCache;1815 {1816 switch (boundaryFiber.tag) {1817 case SuspenseComponent:1818 retryCache = boundaryFiber.stateNode;1819 var suspenseState = boundaryFiber.memoizedState;1820 if (suspenseState !== null) {1821 retryLane = suspenseState.retryLane;1822 }1823 break;1824 case SuspenseListComponent:1825 retryCache = boundaryFiber.stateNode;1826 break;1827 default:1828 {1829 {1830 throw Error( "Pinged unknown suspense boundary type. This is probably a bug in React." );1831 }1832 }1833 }1834 }1835 if (retryCache !== null) {1836 // The wakeable resolved, so we no longer need to memoize, because it will1837 // never be thrown again.1838 retryCache.delete(wakeable);1839 }1840 retryTimedOutBoundary(boundaryFiber, retryLane);1841 } // Computes the next Just Noticeable Difference (JND) boundary.1842 // The theory is that a person can't tell the difference between small differences in time.1843 // Therefore, if we wait a bit longer than necessary that won't translate to a noticeable1844 // difference in the experience. However, waiting for longer might mean that we can avoid1845 // showing an intermediate loading state. The longer we have already waited, the harder it1846 // is to tell small differences in time. Therefore, the longer we've already waited,1847 // the longer we can wait additionally. At some point we have to give up though.1848 // We pick a train model where the next boundary commits at a consistent schedule.1849 // These particular numbers are vague estimates. We expect to adjust them based on research.1850 function jnd(timeElapsed) {1851 return timeElapsed < 120 ? 120 : timeElapsed < 480 ? 480 : timeElapsed < 1080 ? 1080 : timeElapsed < 1920 ? 1920 : timeElapsed < 3000 ? 3000 : timeElapsed < 4320 ? 4320 : ceil(timeElapsed / 1960) * 1960;1852 }1853 function checkForNestedUpdates() {1854 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {1855 nestedUpdateCount = 0;1856 rootWithNestedUpdates = null;1857 {1858 {1859 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." );1860 }1861 }1862 }1863 {1864 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {1865 nestedPassiveUpdateCount = 0;1866 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.');1867 }1868 }1869 }1870 function flushRenderPhaseStrictModeWarningsInDEV() {1871 {1872 ReactStrictModeWarnings.flushLegacyContextWarning();1873 {1874 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();1875 }1876 }1877 }1878 var didWarnStateUpdateForNotYetMountedComponent = null;1879 function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {1880 {1881 if ((executionContext & RenderContext) !== NoContext) {1882 // We let the other warning about render phase updates deal with this one.1883 return;1884 }1885 if (!(fiber.mode & (BlockingMode | ConcurrentMode))) {1886 return;1887 }1888 var tag = fiber.tag;1889 if (tag !== IndeterminateComponent && tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {1890 // Only warn for user-defined components, not internal ones like Suspense.1891 return;1892 } // We show the whole stack but dedupe on the top component's name because1893 // the problematic code almost always lies inside that component.1894 var componentName = getComponentName(fiber.type) || 'ReactComponent';1895 if (didWarnStateUpdateForNotYetMountedComponent !== null) {1896 if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {1897 return;1898 }1899 didWarnStateUpdateForNotYetMountedComponent.add(componentName);1900 } else {1901 didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);1902 }1903 var previousFiber = current;1904 try {1905 setCurrentFiber(fiber);1906 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.');1907 } finally {1908 if (previousFiber) {1909 setCurrentFiber(fiber);1910 } else {1911 resetCurrentFiber();1912 }1913 }1914 }1915 }1916 var didWarnStateUpdateForUnmountedComponent = null;1917 function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {1918 {1919 var tag = fiber.tag;1920 if (tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {1921 // Only warn for user-defined components, not internal ones like Suspense.1922 return;1923 } // If there are pending passive effects unmounts for this Fiber,1924 // we can assume that they would have prevented this update.1925 if ((fiber.flags & PassiveUnmountPendingDev) !== NoFlags) {1926 return;1927 } // We show the whole stack but dedupe on the top component's name because1928 // the problematic code almost always lies inside that component.1929 var componentName = getComponentName(fiber.type) || 'ReactComponent';1930 if (didWarnStateUpdateForUnmountedComponent !== null) {1931 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {1932 return;1933 }1934 didWarnStateUpdateForUnmountedComponent.add(componentName);1935 } else {1936 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);1937 }1938 if (isFlushingPassiveEffects) ; else {1939 var previousFiber = current;1940 try {1941 setCurrentFiber(fiber);1942 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');1943 } finally {1944 if (previousFiber) {1945 setCurrentFiber(fiber);1946 } else {1947 resetCurrentFiber();1948 }1949 }1950 }1951 }1952 }1953 var beginWork$1;1954 {1955 var dummyFiber = null;1956 beginWork$1 = function (current, unitOfWork, lanes) {1957 // If a component throws an error, we replay it again in a synchronously1958 // dispatched event, so that the debugger will treat it as an uncaught1959 // error See ReactErrorUtils for more information.1960 // Before entering the begin phase, copy the work-in-progress onto a dummy1961 // fiber. If beginWork throws, we'll use this to reset the state.1962 var originalWorkInProgressCopy = assignFiberPropertiesInDEV(dummyFiber, unitOfWork);1963 try {1964 return beginWork(current, unitOfWork, lanes);1965 } catch (originalError) {1966 if (originalError !== null && typeof originalError === 'object' && typeof originalError.then === 'function') {1967 // Don't replay promises. Treat everything else like an error.1968 throw originalError;1969 } // Keep this code in sync with handleError; any changes here must have1970 // corresponding changes there.1971 resetContextDependencies();1972 resetHooksAfterThrow(); // Don't reset current debug fiber, since we're about to work on the1973 // same fiber again.1974 // Unwind the failed stack frame1975 unwindInterruptedWork(unitOfWork); // Restore the original properties of the fiber.1976 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);1977 if ( unitOfWork.mode & ProfileMode) {1978 // Reset the profiler timer.1979 startProfilerTimer(unitOfWork);1980 } // Run beginWork again.1981 invokeGuardedCallback(null, beginWork, null, current, unitOfWork, lanes);1982 if (hasCaughtError()) {1983 var replayError = clearCaughtError(); // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.1984 // Rethrow this error instead of the original one.1985 throw replayError;1986 } else {1987 // This branch is reachable if the render phase is impure.1988 throw originalError;1989 }1990 }1991 };1992 }1993 var didWarnAboutUpdateInRender = false;1994 var didWarnAboutUpdateInRenderForAnotherComponent;1995 {1996 didWarnAboutUpdateInRenderForAnotherComponent = new Set();1997 }1998 function warnAboutRenderPhaseUpdatesInDEV(fiber) {1999 {2000 if (isRendering && (executionContext & RenderContext) !== NoContext && !getIsUpdatingOpaqueValueInRenderPhaseInDEV()) {2001 switch (fiber.tag) {2002 case FunctionComponent:2003 case ForwardRef:2004 case SimpleMemoComponent:2005 {2006 var renderingComponentName = workInProgress && getComponentName(workInProgress.type) || 'Unknown'; // Dedupe by the rendering component because it's the one that needs to be fixed.2007 var dedupeKey = renderingComponentName;2008 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {2009 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);2010 var setStateComponentName = getComponentName(fiber.type) || 'Unknown';2011 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);2012 }2013 break;2014 }2015 case ClassComponent:2016 {2017 if (!didWarnAboutUpdateInRender) {2018 error('Cannot update during an existing state transition (such as ' + 'within `render`). Render methods should be a pure ' + 'function of props and state.');2019 didWarnAboutUpdateInRender = true;2020 }2021 break;2022 }2023 }2024 }2025 }2026 } // a 'shared' variable that changes when act() opens/closes in tests.2027 var IsThisRendererActing = {2028 current: false2029 };2030 function warnIfNotScopedWithMatchingAct(fiber) {2031 {2032 if ( IsSomeRendererActing.current === true && IsThisRendererActing.current !== true) {2033 var previousFiber = current;2034 try {2035 setCurrentFiber(fiber);2036 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.2037 '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.2038 'import TestRenderer fr' + "om react-test-renderer';\n" + 'const {act} = TestRenderer;\n' + '// ...\n' + 'act(() => ...);');2039 } finally {2040 if (previousFiber) {2041 setCurrentFiber(fiber);2042 } else {2043 resetCurrentFiber();2044 }2045 }2046 }2047 }2048 }2049 function warnIfNotCurrentlyActingEffectsInDEV(fiber) {2050 {2051 if ( (fiber.mode & StrictMode) !== NoMode && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {2052 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));2053 }2054 }2055 }2056 function warnIfNotCurrentlyActingUpdatesInDEV(fiber) {2057 {2058 if ( executionContext === NoContext && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {2059 var previousFiber = current;2060 try {2061 setCurrentFiber(fiber);2062 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));2063 } finally {2064 if (previousFiber) {2065 setCurrentFiber(fiber);2066 } else {2067 resetCurrentFiber();2068 }2069 }2070 }2071 }2072 }2073 var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; // In tests, we want to enforce a mocked scheduler.2074 var didWarnAboutUnmockedScheduler = false; // TODO Before we release concurrent mode, revisit this and decide whether a mocked2075 // scheduler is the actual recommendation. The alternative could be a testing build,2076 // a new lib, or whatever; we dunno just yet. This message is for early adopters2077 // to get their tests right.2078 function warnIfUnmockedScheduler(fiber) {2079 {2080 if (didWarnAboutUnmockedScheduler === false && unstable_flushAllWithoutAsserting === undefined) {2081 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) {2082 didWarnAboutUnmockedScheduler = true;2083 error('In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' + 'to guarantee consistent behaviour across tests and browsers. ' + 'For example, with jest: \n' + // Break up requires to avoid accidentally parsing them as dependencies.2084 "jest.mock('scheduler', () => require" + "('scheduler/unstable_mock'));\n\n" + 'For more info, visit https://reactjs.org/link/mock-scheduler');2085 }2086 }2087 }2088 }2089 function computeThreadID(root, lane) {2090 // Interaction threads are unique per root and expiration time.2091 // NOTE: Intentionally unsound cast. All that matters is that it's a number2092 // and it represents a batch of work. Could make a helper function instead,2093 // but meh this is fine for now.2094 return lane * 1000 + root.interactionThreadID;2095 }2096 function markSpawnedWork(lane) {2097 if (spawnedWorkDuringRender === null) {2098 spawnedWorkDuringRender = [lane];2099 } else {2100 spawnedWorkDuringRender.push(lane);2101 }2102 }2103 function scheduleInteractions(root, lane, interactions) {2104 if (interactions.size > 0) {2105 var pendingInteractionMap = root.pendingInteractionMap;2106 var pendingInteractions = pendingInteractionMap.get(lane);2107 if (pendingInteractions != null) {2108 interactions.forEach(function (interaction) {2109 if (!pendingInteractions.has(interaction)) {2110 // Update the pending async work count for previously unscheduled interaction.2111 interaction.__count++;2112 }2113 pendingInteractions.add(interaction);2114 });2115 } else {2116 pendingInteractionMap.set(lane, new Set(interactions)); // Update the pending async work count for the current interactions.2117 interactions.forEach(function (interaction) {2118 interaction.__count++;2119 });2120 }2121 var subscriber = __subscriberRef.current;2122 if (subscriber !== null) {2123 var threadID = computeThreadID(root, lane);2124 subscriber.onWorkScheduled(interactions, threadID);2125 }2126 }2127 }2128 function schedulePendingInteractions(root, lane) {2129 scheduleInteractions(root, lane, __interactionsRef.current);2130 }2131 function startWorkOnPendingInteractions(root, lanes) {2132 // we can accurately attribute time spent working on it, And so that cascading2133 // work triggered during the render phase will be associated with it.2134 var interactions = new Set();2135 root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledLane) {2136 if (includesSomeLane(lanes, scheduledLane)) {2137 scheduledInteractions.forEach(function (interaction) {2138 return interactions.add(interaction);2139 });2140 }2141 }); // Store the current set of interactions on the FiberRoot for a few reasons:2142 // We can re-use it in hot functions like performConcurrentWorkOnRoot()...
ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js
...259 // Check if we're not already rendering260 (executionContext & (RenderContext | CommitContext)) === NoContext261 ) {262 // Register pending interactions on the root to avoid losing traced interaction data.263 schedulePendingInteractions(root, lane);264 // This is a legacy edge case. The initial mount of a ReactDOM.render-ed265 // root inside of batchedUpdates should be synchronous, but layout updates266 // should be deferred until the end of the batch.267 console.log("performSyncWorkOnRoot");268 performSyncWorkOnRoot(root);269 } else {270 ensureRootIsScheduled(root, eventTime);271 schedulePendingInteractions(root, lane);272 if (executionContext === NoContext) {273 // Flush the synchronous work now, unless we're already working or inside274 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of275 // scheduleCallbackForFiber to preserve the ability to schedule a callback276 // without immediately flushing it. We only do this for user-initiated277 // updates, to preserve historical behavior of legacy mode.278 resetRenderTimer();279 flushSyncCallbackQueue();280 }281 }282 } else {283 // Schedule a discrete update but only if it's not Sync.284 if (285 (executionContext & DiscreteEventContext) !== NoContext &&286 // Only updates at user-blocking priority or greater are considered287 // discrete, even inside a discrete event.288 (priorityLevel === UserBlockingSchedulerPriority ||289 priorityLevel === ImmediateSchedulerPriority)290 ) {291 // This is the result of a discrete event. Track the lowest priority292 // discrete update per root so we can flush them early, if needed.293 if (rootsWithPendingDiscreteUpdates === null) {294 rootsWithPendingDiscreteUpdates = new Set([root]);295 } else {296 rootsWithPendingDiscreteUpdates.add(root);297 }298 }299 // Schedule other updates after in case the callback is sync.300 ensureRootIsScheduled(root, eventTime);301 schedulePendingInteractions(root, lane);302 }303 // We use this when assigning a lane for a transition inside304 // `requestUpdateLane`. We assume it's the same as the root being updated,305 // since in the common case of a single root app it probably is. If it's not306 // the same root, then it's not a huge deal, we just might batch more stuff307 // together more than necessary.308 mostRecentlyUpdatedRoot = root;309 return root;310}311function schedulePendingInteractions(root, lane) {312 // This is called when work is scheduled on a root.313 // It associates the current interactions with the newly-scheduled expiration.314 // They will be restored when that expiration is later committed.315 // if (!enableSchedulerTracing) {316 // return;317 // }318 // scheduleInteractions(root, lane, __interactionsRef.current);319}320// This is the entry point for synchronous tasks that don't go321// through Scheduler322function performSyncWorkOnRoot(root) {323 // if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {324 // syncNestedUpdateFlag();325 // }...
scheduleUpdateOnFiber.js
Source:scheduleUpdateOnFiber.js
...14 if ( // Check if we're inside unbatchedUpdates15 (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering16 (executionContext & (RenderContext | CommitContext)) === NoContext) {17 // Register pending interactions on the root to avoid losing traced interaction data.18 schedulePendingInteractions(root, expirationTime); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed19 // root inside of batchedUpdates should be synchronous, but layout updates20 // should be deferred until the end of the batch.21 performSyncWorkOnRoot(root);22 } else {23 ensureRootIsScheduled(root);24 schedulePendingInteractions(root, expirationTime);25 if (executionContext === NoContext) {26 // Flush the synchronous work now, unless we're already working or inside27 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of28 // scheduleCallbackForFiber to preserve the ability to schedule a callback29 // without immediately flushing it. We only do this for user-initiated30 // updates, to preserve historical behavior of sync mode.31 flushSyncCallbackQueue();32 }33 }34 } else {35 ensureRootIsScheduled(root);36 schedulePendingInteractions(root, expirationTime);37 }38 if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered39 // discrete, even inside a discrete event.40 priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority)) {41 // This is the result of a discrete event. Track the lowest priority42 // discrete update per root so we can flush them early, if needed.43 if (rootsWithPendingDiscreteUpdates === null) {44 rootsWithPendingDiscreteUpdates = new Map([45 [root, expirationTime]46 ]);47 } else {48 var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);49 if (lastDiscreteTime === undefined || lastDiscreteTime > expirationTime) {50 rootsWithPendingDiscreteUpdates.set(root, expirationTime);...
1-2__scheduleUpdateOnFiber.js
Source:1-2__scheduleUpdateOnFiber.js
...14 if ( // Check if we're inside unbatchedUpdates15 (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering16 (executionContext & (RenderContext | CommitContext)) === NoContext) {17 // Register pending interactions on the root to avoid losing traced interaction data.18 schedulePendingInteractions(root, expirationTime); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed19 // root inside of batchedUpdates should be synchronous, but layout updates20 // should be deferred until the end of the batch.21 performSyncWorkOnRoot(root);22 } else {23 ensureRootIsScheduled(root);24 schedulePendingInteractions(root, expirationTime);25 if (executionContext === NoContext) {26 // Flush the synchronous work now, unless we're already working or inside27 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of28 // scheduleCallbackForFiber to preserve the ability to schedule a callback29 // without immediately flushing it. We only do this for user-initiated30 // updates, to preserve historical behavior of sync mode.31 flushSyncCallbackQueue();32 }33 }34 } else {35 ensureRootIsScheduled(root);36 schedulePendingInteractions(root, expirationTime);37 }38 if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered39 // discrete, even inside a discrete event.40 priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority)) {41 // This is the result of a discrete event. Track the lowest priority42 // discrete update per root so we can flush them early, if needed.43 if (rootsWithPendingDiscreteUpdates === null) {44 rootsWithPendingDiscreteUpdates = new Map([45 [root, expirationTime]46 ]);47 } else {48 var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);49 if (lastDiscreteTime === undefined || lastDiscreteTime > expirationTime) {50 rootsWithPendingDiscreteUpdates.set(root, expirationTime);...
updateEqueue.js
Source:updateEqueue.js
...59 if (60 (executionContext & LegacyUnbatchedContext) !== NoContext &&61 (executionContext & (RenderContext | CommitContext)) === NoContext62 ) {63 schedulePendingInteractions(root, expirationTime);64 performSyncWorkOnRoot(root);65 } else {66 ensureRootIsScheduled(root);67 schedulePendingInteractions(root, expirationTime);68 if (executionContext === NoContext) {69 flushSyncCallbackQueue();70 }71 }72 } else {73 ensureRootIsScheduled(root);74 schedulePendingInteractions(root, expirationTime);75 }76 if (77 (executionContext & DiscreteEventContext) !== NoContext &&78 (priorityLevel === UserBlockingPriority ||79 priorityLevel === ImmediatePriority)80 ) {81 if (rootsWithPendingDiscreteUpdates === null) {82 rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]);83 } else {84 const lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);85 if (lastDiscreteTime === undefined || lastDiscreteTime > expirationTime) {86 rootsWithPendingDiscreteUpdates.set(root, expirationTime);87 }88 }...
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForTimeout(10000);7 await page.evaluate(() => {8 const { schedulePendingInteractions } = window.playwright._internal;9 schedulePendingInteractions();10 });11 await page.screenshot({ path: 'google.png' });12 await browser.close();13})();
Using AI Code Generation
1const { schedulePendingInteractions } = require('playwright/lib/server/frames');2const { schedulePendingInteractions } = require('playwright/lib/server/frames');3const { schedulePendingInteractions } = require('playwright/lib/server/frames');4const { schedulePendingInteractions } = require('playwright/lib/server/frames');5const { schedulePendingInteractions } = require('playwright/lib/server/frames');6const { schedulePendingInteractions } = require('playwright/lib/server/frames');7const { schedulePendingInteractions } = require('playwright/lib/server/frames');8const { schedulePendingInteractions } = require('playwright/lib/server/frames');9const { schedulePendingInteractions } = require('playwright/lib/server/frames');10const { schedulePendingInteractions } = require('playwright/lib/server/frames');11const { schedulePendingInteractions } = require('playwright/lib/server/frames');12const { schedulePendingInteractions } = require('playwright/lib/server/frames');13const { schedulePendingInteractions } = require('playwright/lib/server/frames');14const { schedulePendingInteractions } = require('playwright/lib/server/frames');15const { schedulePendingInteractions } = require('playwright/lib/server/frames');16const { schedulePendingInteractions } = require('playwright/lib/server/frames');
Using AI Code Generation
1const playwright = require('playwright');2const { schedulePendingInteractions } = require('playwright/lib/internal/inspector/inspector');3(async () => {4 const browser = await playwright.chromium.launch();5 const page = await browser.newPage();6 await page.click('text=Docs');7 await schedulePendingInteractions(page);8 await browser.close();9})();
Using AI Code Generation
1const playwright = require('playwright');2const { schedulePendingInteractions } = require('playwright/lib/internal/scheduler');3const { chromium } = require('playwright');4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();8 const input = await page.$('input');9 await input.click();10 await input.type('hello');11 await schedulePendingInteractions(page);12 await browser.close();13})();14const playwright = require('playwright');15const { schedulePendingInteractions } = require('playwright/lib/internal/scheduler');16const { chromium } = require('playwright');17describe('My test', () => {18 let browser;19 let context;20 let page;21 beforeAll(async () => {22 browser = await chromium.launch();23 context = await browser.newContext();24 page = await context.newPage();25 });26 afterAll(async () => {27 await browser.close();28 });29 it('should work', async () => {30 const input = await page.$('input');31 await input.click();32 await input.type('hello');33 await schedulePendingInteractions(page);34 });35});36const playwright = require('playwright');37const { schedulePendingInteractions } = require('playwright/lib/internal/scheduler');38const { chromium } = require('playwright');39describe('My test', () => {40 let browser;41 let context;42 let page;43 beforeAll(async () => {44 browser = await chromium.launch();45 context = await browser.newContext();46 page = await context.newPage();47 });48 afterAll(async () => {49 await browser.close();50 });51 it('should work', async () => {52 const input = await page.$('input');53 await input.click();54 await input.type('hello');55 await schedulePendingInteractions(page);56 });57 it('should work again', async () => {58 const input = await page.$('input');59 await input.click();60 await input.type('
Using AI Code Generation
1const playwright = require('playwright');2const { schedulePendingInteractions } = require('playwright/lib/internal/inspectorInstrumentation');3const { chromium } = playwright;4(async () => {5 const browser = await chromium.launch({ headless: false });6 const context = await browser.newContext();7 const page = await context.newPage();8 await schedulePendingInteractions();9 await page.screenshot({ path: 'google.png' });10 await browser.close();11})();12{13 "scripts": {14 },15 "dependencies": {16 }17}
Using AI Code Generation
1const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.fill('input[name="q"]', 'Playwright');8 await page.click('input[type="submit"]');9 await page.waitForSelector('text=Playwright');10 {11 'position': { x: 0, y: 0 },12 },13 ];14 await schedulePendingInteractions(page, interactions);15 await page.waitForTimeout(10000);16 await browser.close();17})();
Using AI Code Generation
1const playwright = require('playwright');2const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');3(async () => {4 const browser = await playwright['chromium'].launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await schedulePendingInteractions(page);8 await browser.close();9})();10const playwright = require('playwright');11const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');12(async () => {13 const browser = await playwright['chromium'].launch();14 const context = await browser.newContext();15 const page = await context.newPage();16 await schedulePendingInteractions(page);17 await browser.close();18})();19const playwright = require('playwright');20const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');21(async () => {22 const browser = await playwright['chromium'].launch();23 const context = await browser.newContext();24 const page = await context.newPage();25 await schedulePendingInteractions(page);26 await browser.close();27})();28const playwright = require('playwright');29const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');30(async () => {31 const browser = await playwright['chromium'].launch();32 const context = await browser.newContext();33 const page = await context.newPage();34 await schedulePendingInteractions(page);35 await browser.close();36})();37const playwright = require('playwright');38const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');39(async () => {40 const browser = await playwright['chromium'].launch();
Using AI Code Generation
1const { schedulePendingInteractions } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');2schedulePendingInteractions(page);3const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');4scheduleInteraction(page, () => {5});6const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');7scheduleInteraction(page, () => {8});9const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');10scheduleInteraction(page, () => {11});12const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');13scheduleInteraction(page, () => {14});15const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');16scheduleInteraction(page, () => {17});18const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');19scheduleInteraction(page, () => {20});21const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');22scheduleInteraction(page, () => {23});24const { scheduleInteraction } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');25scheduleInteraction(page, () => {26});27const { scheduleInteraction } = require('playwright/lib/server
Using AI Code Generation
1const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');2schedulePendingInteractions();3const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');4module.exports = {5 use: {6 launchOptions: {7 },8 },9 {10 use: {11 launchOptions: {12 },13 },14 },15 ['json', { outputFile: 'reports/json/report.json' }],16 ['junit', { outputFile: 'reports/junit/report.xml' }],17 {18 use: {19 },20 },21};22const { test, expect } = require('@playwright/test');23const { schedulePendingInteractions } = require('playwright/lib/internal/inspector');24test('test', async ({ page }) => {25 await page.click('#tsf > div:nth-child(2) > div > div.RNNXgb > div > div.a4bIc > input');26 await page.fill('#tsf > div:nth-child(2) > div > div.RNNXgb > div > div.a4bIc > input', 'test');27 await page.click('body >
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!