Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.new.js
Source:ReactFiberWorkLoop.new.js
...706 workInProgressRootLatestProcessedEventTime === Sync;707 if (708 hasNotProcessedNewUpdates &&709 // do not delay if we're inside an act() scope710 !shouldForceFlushFallbacksInDEV()711 ) {712 // If we have not processed any new updates during this pass, then713 // this is either a retry of an existing fallback state or a714 // hidden tree. Hidden trees shouldn't be batched with other work715 // and after that's fixed it can only be a retry. We're going to716 // throttle committing retries so that we don't show too many717 // loading states too quickly.718 const msUntilTimeout =719 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();720 // Don't bother with a very short suspense time.721 if (msUntilTimeout > 10) {722 if (workInProgressRootHasPendingPing) {723 const lastPingedTime = root.lastPingedTime;724 if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) {725 // This render was pinged but we didn't get to restart726 // earlier so try restarting now instead.727 root.lastPingedTime = expirationTime;728 prepareFreshStack(root, expirationTime);729 break;730 }731 }732 const nextTime = getNextRootExpirationTimeToWorkOn(root);733 if (nextTime !== NoWork && nextTime !== expirationTime) {734 // There's additional work on this root.735 break;736 }737 if (738 lastSuspendedTime !== NoWork &&739 lastSuspendedTime !== expirationTime740 ) {741 // We should prefer to render the fallback of at the last742 // suspended level. Ping the last suspended level to try743 // rendering it again.744 root.lastPingedTime = lastSuspendedTime;745 break;746 }747 // The render is suspended, it hasn't timed out, and there's no748 // lower priority work to do. Instead of committing the fallback749 // immediately, wait for more data to arrive.750 root.timeoutHandle = scheduleTimeout(751 commitRoot.bind(null, root),752 msUntilTimeout,753 );754 break;755 }756 }757 // The work expired. Commit immediately.758 commitRoot(root);759 break;760 }761 case RootSuspendedWithDelay: {762 markRootSuspendedAtTime(root, expirationTime);763 const lastSuspendedTime = root.lastSuspendedTime;764 if (765 // do not delay if we're inside an act() scope766 !shouldForceFlushFallbacksInDEV()767 ) {768 // We're suspended in a state that should be avoided. We'll try to769 // avoid committing it for as long as the timeouts let us.770 if (workInProgressRootHasPendingPing) {771 const lastPingedTime = root.lastPingedTime;772 if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) {773 // This render was pinged but we didn't get to restart earlier774 // so try restarting now instead.775 root.lastPingedTime = expirationTime;776 prepareFreshStack(root, expirationTime);777 break;778 }779 }780 const nextTime = getNextRootExpirationTimeToWorkOn(root);781 if (nextTime !== NoWork && nextTime !== expirationTime) {782 // There's additional work on this root.783 break;784 }785 if (786 lastSuspendedTime !== NoWork &&787 lastSuspendedTime !== expirationTime788 ) {789 // We should prefer to render the fallback of at the last790 // suspended level. Ping the last suspended level to try791 // rendering it again.792 root.lastPingedTime = lastSuspendedTime;793 break;794 }795 let msUntilTimeout;796 if (workInProgressRootLatestSuspenseTimeout !== Sync) {797 // We have processed a suspense config whose expiration time we798 // can use as the timeout.799 msUntilTimeout =800 expirationTimeToMs(workInProgressRootLatestSuspenseTimeout) - now();801 } else if (workInProgressRootLatestProcessedEventTime === Sync) {802 // This should never normally happen because only new updates803 // cause delayed states, so we should have processed something.804 // However, this could also happen in an offscreen tree.805 msUntilTimeout = 0;806 } else {807 // If we didn't process a suspense config, compute a JND based on808 // the amount of time elapsed since the most recent event time.809 const eventTimeMs = expirationTimeToMs(810 workInProgressRootLatestProcessedEventTime,811 );812 const timeElapsedMs = now() - eventTimeMs;813 msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs;814 }815 // Don't bother with a very short suspense time.816 if (msUntilTimeout > 10) {817 // The render is suspended, it hasn't timed out, and there's no818 // lower priority work to do. Instead of committing the fallback819 // immediately, wait for more data to arrive.820 root.timeoutHandle = scheduleTimeout(821 commitRoot.bind(null, root),822 msUntilTimeout,823 );824 break;825 }826 }827 // The work expired. Commit immediately.828 commitRoot(root);829 break;830 }831 case RootCompleted: {832 // The work completed. Ready to commit.833 if (834 // do not delay if we're inside an act() scope835 !shouldForceFlushFallbacksInDEV() &&836 workInProgressRootLatestProcessedEventTime !== Sync &&837 workInProgressRootCanSuspendUsingConfig !== null838 ) {839 // If we have exceeded the minimum loading delay, which probably840 // means we have shown a spinner already, we might have to suspend841 // a bit longer to ensure that the spinner is shown for842 // enough time.843 const msUntilTimeout = computeMsUntilSuspenseLoadingDelay(844 workInProgressRootLatestProcessedEventTime,845 expirationTime,846 workInProgressRootCanSuspendUsingConfig,847 );848 if (msUntilTimeout > 10) {849 markRootSuspendedAtTime(root, expirationTime);850 root.timeoutHandle = scheduleTimeout(851 commitRoot.bind(null, root),852 msUntilTimeout,853 );854 break;855 }856 }857 commitRoot(root);858 break;859 }860 default: {861 invariant(false, 'Unknown root exit status.');862 }863 }864}865// This is the entry point for synchronous tasks that don't go866// through Scheduler867function performSyncWorkOnRoot(root) {868 invariant(869 (executionContext & (RenderContext | CommitContext)) === NoContext,870 'Should not already be working.',871 );872 flushPassiveEffects();873 const lastExpiredTime = root.lastExpiredTime;874 let expirationTime;875 if (lastExpiredTime !== NoWork) {876 // There's expired work on this root. Check if we have a partial tree877 // that we can reuse.878 if (879 root === workInProgressRoot &&880 renderExpirationTime >= lastExpiredTime881 ) {882 // There's a partial tree with equal or greater than priority than the883 // expired level. Finish rendering it before rendering the rest of the884 // expired work.885 expirationTime = renderExpirationTime;886 } else {887 // Start a fresh tree.888 expirationTime = lastExpiredTime;889 }890 } else {891 // There's no expired work. This must be a new, synchronous render.892 expirationTime = Sync;893 }894 let exitStatus = renderRootSync(root, expirationTime);895 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {896 // If something threw an error, try rendering one more time. We'll897 // render synchronously to block concurrent data mutations, and we'll898 // render at Idle (or lower) so that all pending updates are included.899 // If it still fails after the second attempt, we'll give up and commit900 // the resulting tree.901 expirationTime = expirationTime > Idle ? Idle : expirationTime;902 exitStatus = renderRootSync(root, expirationTime);903 }904 if (exitStatus === RootFatalErrored) {905 const fatalError = workInProgressRootFatalError;906 prepareFreshStack(root, expirationTime);907 markRootSuspendedAtTime(root, expirationTime);908 ensureRootIsScheduled(root);909 throw fatalError;910 }911 // We now have a consistent tree. Because this is a sync render, we912 // will commit it even if something suspended.913 const finishedWork: Fiber = (root.current.alternate: any);914 root.finishedWork = finishedWork;915 root.finishedExpirationTime = expirationTime;916 root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork);917 commitRoot(root);918 // Before exiting, make sure there's a callback scheduled for the next919 // pending level.920 ensureRootIsScheduled(root);921 return null;922}923export function flushRoot(root: FiberRoot, expirationTime: ExpirationTime) {924 markRootExpiredAtTime(root, expirationTime);925 ensureRootIsScheduled(root);926 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {927 flushSyncCallbackQueue();928 }929}930export function flushDiscreteUpdates() {931 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.932 // However, `act` uses `batchedUpdates`, so there's no way to distinguish933 // those two cases. Need to fix this before exposing flushDiscreteUpdates934 // as a public API.935 if (936 (executionContext & (BatchedContext | RenderContext | CommitContext)) !==937 NoContext938 ) {939 if (__DEV__) {940 if ((executionContext & RenderContext) !== NoContext) {941 console.error(942 'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +943 'already rendering.',944 );945 }946 }947 // We're already rendering, so we can't synchronously flush pending work.948 // This is probably a nested event dispatch triggered by a lifecycle/effect,949 // like `el.focus()`. Exit.950 return;951 }952 flushPendingDiscreteUpdates();953 // If the discrete updates scheduled passive effects, flush them now so that954 // they fire before the next serial event.955 flushPassiveEffects();956}957export function deferredUpdates<A>(fn: () => A): A {958 // TODO: Remove in favor of Scheduler.next959 return runWithPriority(NormalPriority, fn);960}961export function syncUpdates<A, B, C, R>(962 fn: (A, B, C) => R,963 a: A,964 b: B,965 c: C,966): R {967 return runWithPriority(ImmediatePriority, fn.bind(null, a, b, c));968}969function flushPendingDiscreteUpdates() {970 if (rootsWithPendingDiscreteUpdates !== null) {971 // For each root with pending discrete updates, schedule a callback to972 // immediately flush them.973 const roots = rootsWithPendingDiscreteUpdates;974 rootsWithPendingDiscreteUpdates = null;975 roots.forEach((expirationTime, root) => {976 markRootExpiredAtTime(root, expirationTime);977 ensureRootIsScheduled(root);978 });979 // Now flush the immediate queue.980 flushSyncCallbackQueue();981 }982}983export function batchedUpdates<A, R>(fn: A => R, a: A): R {984 const prevExecutionContext = executionContext;985 executionContext |= BatchedContext;986 try {987 return fn(a);988 } finally {989 executionContext = prevExecutionContext;990 if (executionContext === NoContext) {991 // Flush the immediate callbacks that were scheduled during this batch992 flushSyncCallbackQueue();993 }994 }995}996export function batchedEventUpdates<A, R>(fn: A => R, a: A): R {997 const prevExecutionContext = executionContext;998 executionContext |= EventContext;999 try {1000 return fn(a);1001 } finally {1002 executionContext = prevExecutionContext;1003 if (executionContext === NoContext) {1004 // Flush the immediate callbacks that were scheduled during this batch1005 flushSyncCallbackQueue();1006 }1007 }1008}1009export function discreteUpdates<A, B, C, D, R>(1010 fn: (A, B, C) => R,1011 a: A,1012 b: B,1013 c: C,1014 d: D,1015): R {1016 const prevExecutionContext = executionContext;1017 executionContext |= DiscreteEventContext;1018 try {1019 // Should this1020 return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c, d));1021 } finally {1022 executionContext = prevExecutionContext;1023 if (executionContext === NoContext) {1024 // Flush the immediate callbacks that were scheduled during this batch1025 flushSyncCallbackQueue();1026 }1027 }1028}1029export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {1030 const prevExecutionContext = executionContext;1031 executionContext &= ~BatchedContext;1032 executionContext |= LegacyUnbatchedContext;1033 try {1034 return fn(a);1035 } finally {1036 executionContext = prevExecutionContext;1037 if (executionContext === NoContext) {1038 // Flush the immediate callbacks that were scheduled during this batch1039 flushSyncCallbackQueue();1040 }1041 }1042}1043export function flushSync<A, R>(fn: A => R, a: A): R {1044 if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {1045 invariant(1046 false,1047 'flushSync was called from inside a lifecycle method. It cannot be ' +1048 'called when React is already rendering.',1049 );1050 }1051 const prevExecutionContext = executionContext;1052 executionContext |= BatchedContext;1053 try {1054 return runWithPriority(ImmediatePriority, fn.bind(null, a));1055 } finally {1056 executionContext = prevExecutionContext;1057 // Flush the immediate callbacks that were scheduled during this batch.1058 // Note that this will happen even if batchedUpdates is higher up1059 // the stack.1060 flushSyncCallbackQueue();1061 }1062}1063export function flushControlled(fn: () => mixed): void {1064 const prevExecutionContext = executionContext;1065 executionContext |= BatchedContext;1066 try {1067 runWithPriority(ImmediatePriority, fn);1068 } finally {1069 executionContext = prevExecutionContext;1070 if (executionContext === NoContext) {1071 // Flush the immediate callbacks that were scheduled during this batch1072 flushSyncCallbackQueue();1073 }1074 }1075}1076function prepareFreshStack(root, expirationTime) {1077 root.finishedWork = null;1078 root.finishedExpirationTime = NoWork;1079 const timeoutHandle = root.timeoutHandle;1080 if (timeoutHandle !== noTimeout) {1081 // The root previous suspended and scheduled a timeout to commit a fallback1082 // state. Now that we have additional work, cancel the timeout.1083 root.timeoutHandle = noTimeout;1084 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above1085 cancelTimeout(timeoutHandle);1086 }1087 // Check if there's a suspended level at lower priority.1088 const lastSuspendedTime = root.lastSuspendedTime;1089 if (lastSuspendedTime !== NoWork && lastSuspendedTime < expirationTime) {1090 const lastPingedTime = root.lastPingedTime;1091 // Make sure the suspended level is marked as pinged so that we return back1092 // to it later, in case the render we're about to start gets aborted.1093 // Generally we only reach this path via a ping, but we shouldn't assume1094 // that will always be the case.1095 // Note: This is defensive coding to prevent a pending commit from1096 // being dropped without being rescheduled. It shouldn't be necessary.1097 if (lastPingedTime === NoWork || lastPingedTime > lastSuspendedTime) {1098 root.lastPingedTime = lastSuspendedTime;1099 }1100 }1101 if (workInProgress !== null) {1102 let interruptedWork = workInProgress.return;1103 while (interruptedWork !== null) {1104 unwindInterruptedWork(interruptedWork);1105 interruptedWork = interruptedWork.return;1106 }1107 }1108 workInProgressRoot = root;1109 workInProgress = createWorkInProgress(root.current, null);1110 renderExpirationTime = expirationTime;1111 workInProgressRootExitStatus = RootIncomplete;1112 workInProgressRootFatalError = null;1113 workInProgressRootLatestProcessedEventTime = Sync;1114 workInProgressRootLatestSuspenseTimeout = Sync;1115 workInProgressRootCanSuspendUsingConfig = null;1116 workInProgressRootNextUnprocessedUpdateTime = NoWork;1117 workInProgressRootHasPendingPing = false;1118 if (enableSchedulerTracing) {1119 spawnedWorkDuringRender = null;1120 }1121 if (__DEV__) {1122 ReactStrictModeWarnings.discardPendingWarnings();1123 }1124}1125function handleError(root, thrownValue): void {1126 do {1127 let erroredWork = workInProgress;1128 try {1129 // Reset module-level state that was set during the render phase.1130 resetContextDependencies();1131 resetHooksAfterThrow();1132 resetCurrentDebugFiberInDEV();1133 // TODO: I found and added this missing line while investigating a1134 // separate issue. Write a regression test using string refs.1135 ReactCurrentOwner.current = null;1136 if (erroredWork === null || erroredWork.return === null) {1137 // Expected to be working on a non-root fiber. This is a fatal error1138 // because there's no ancestor that can handle it; the root is1139 // supposed to capture all errors that weren't caught by an error1140 // boundary.1141 workInProgressRootExitStatus = RootFatalErrored;1142 workInProgressRootFatalError = thrownValue;1143 // Set `workInProgress` to null. This represents advancing to the next1144 // sibling, or the parent if there are no siblings. But since the root1145 // has no siblings nor a parent, we set it to null. Usually this is1146 // handled by `completeUnitOfWork` or `unwindWork`, but since we're1147 // interntionally not calling those, we need set it here.1148 // TODO: Consider calling `unwindWork` to pop the contexts.1149 workInProgress = null;1150 return;1151 }1152 if (enableProfilerTimer && erroredWork.mode & ProfileMode) {1153 // Record the time spent rendering before an error was thrown. This1154 // avoids inaccurate Profiler durations in the case of a1155 // suspended render.1156 stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);1157 }1158 throwException(1159 root,1160 erroredWork.return,1161 erroredWork,1162 thrownValue,1163 renderExpirationTime,1164 );1165 completeUnitOfWork(erroredWork);1166 } catch (yetAnotherThrownValue) {1167 // Something in the return path also threw.1168 thrownValue = yetAnotherThrownValue;1169 if (workInProgress === erroredWork && erroredWork !== null) {1170 // If this boundary has already errored, then we had trouble processing1171 // the error. Bubble it to the next boundary.1172 erroredWork = erroredWork.return;1173 workInProgress = erroredWork;1174 } else {1175 erroredWork = workInProgress;1176 }1177 continue;1178 }1179 // Return to the normal work loop.1180 return;1181 } while (true);1182}1183function pushDispatcher(root) {1184 const prevDispatcher = ReactCurrentDispatcher.current;1185 ReactCurrentDispatcher.current = ContextOnlyDispatcher;1186 if (prevDispatcher === null) {1187 // The React isomorphic package does not include a default dispatcher.1188 // Instead the first renderer will lazily attach one, in order to give1189 // nicer error messages.1190 return ContextOnlyDispatcher;1191 } else {1192 return prevDispatcher;1193 }1194}1195function popDispatcher(prevDispatcher) {1196 ReactCurrentDispatcher.current = prevDispatcher;1197}1198function pushInteractions(root) {1199 if (enableSchedulerTracing) {1200 const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1201 __interactionsRef.current = root.memoizedInteractions;1202 return prevInteractions;1203 }1204 return null;1205}1206function popInteractions(prevInteractions) {1207 if (enableSchedulerTracing) {1208 __interactionsRef.current = prevInteractions;1209 }1210}1211export function markCommitTimeOfFallback() {1212 globalMostRecentFallbackTime = now();1213}1214export function markRenderEventTimeAndConfig(1215 eventTime: ExpirationTime,1216 suspenseConfig: null | SuspenseConfig,1217): void {1218 // Anything lower pri than Idle is not an update, so we should skip it.1219 if (eventTime > Idle) {1220 // Track the most recent event time of all updates processed in this batch.1221 if (workInProgressRootLatestProcessedEventTime > eventTime) {1222 workInProgressRootLatestProcessedEventTime = eventTime;1223 }1224 // Track the largest/latest timeout deadline in this batch.1225 // TODO: If there are two transitions in the same batch, shouldn't we1226 // choose the smaller one? Maybe this is because when an intermediate1227 // transition is superseded, we should ignore its suspense config, but1228 // we don't currently.1229 if (suspenseConfig !== null) {1230 // If `timeoutMs` is not specified, we default to 5 seconds. We have to1231 // resolve this default here because `suspenseConfig` is owned1232 // by userspace.1233 // TODO: Store this on the root instead (transition -> timeoutMs)1234 // TODO: Should this default to a JND instead?1235 const timeoutMs = suspenseConfig.timeoutMs | 0 || LOW_PRIORITY_EXPIRATION;1236 const timeoutTime = computeSuspenseTimeout(eventTime, timeoutMs);1237 if (timeoutTime < workInProgressRootLatestSuspenseTimeout) {1238 workInProgressRootLatestSuspenseTimeout = timeoutTime;1239 workInProgressRootCanSuspendUsingConfig = suspenseConfig;1240 }1241 }1242 }1243}1244export function markUnprocessedUpdateTime(1245 expirationTime: ExpirationTime,1246): void {1247 if (expirationTime > workInProgressRootNextUnprocessedUpdateTime) {1248 workInProgressRootNextUnprocessedUpdateTime = expirationTime;1249 }1250}1251export function renderDidSuspend(): void {1252 if (workInProgressRootExitStatus === RootIncomplete) {1253 workInProgressRootExitStatus = RootSuspended;1254 }1255}1256export function renderDidSuspendDelayIfPossible(): void {1257 if (1258 workInProgressRootExitStatus === RootIncomplete ||1259 workInProgressRootExitStatus === RootSuspended1260 ) {1261 workInProgressRootExitStatus = RootSuspendedWithDelay;1262 }1263 // Check if there's a lower priority update somewhere else in the tree.1264 if (1265 workInProgressRootNextUnprocessedUpdateTime !== NoWork &&1266 workInProgressRoot !== null1267 ) {1268 // Mark the current render as suspended, and then mark that there's a1269 // pending update.1270 // TODO: This should immediately interrupt the current render, instead1271 // of waiting until the next time we yield.1272 markRootSuspendedAtTime(workInProgressRoot, renderExpirationTime);1273 markRootUpdatedAtTime(1274 workInProgressRoot,1275 workInProgressRootNextUnprocessedUpdateTime,1276 );1277 }1278}1279export function renderDidError() {1280 if (workInProgressRootExitStatus !== RootCompleted) {1281 workInProgressRootExitStatus = RootErrored;1282 }1283}1284// Called during render to determine if anything has suspended.1285// Returns false if we're not sure.1286export function renderHasNotSuspendedYet(): boolean {1287 // If something errored or completed, we can't really be sure,1288 // so those are false.1289 return workInProgressRootExitStatus === RootIncomplete;1290}1291function renderRootSync(root, expirationTime) {1292 const prevExecutionContext = executionContext;1293 executionContext |= RenderContext;1294 const prevDispatcher = pushDispatcher(root);1295 // If the root or expiration time have changed, throw out the existing stack1296 // and prepare a fresh one. Otherwise we'll continue where we left off.1297 if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) {1298 prepareFreshStack(root, expirationTime);1299 startWorkOnPendingInteractions(root, expirationTime);1300 }1301 const prevInteractions = pushInteractions(root);1302 if (__DEV__) {1303 if (enableDebugTracing) {1304 const priorityLevel = getCurrentPriorityLevel();1305 const label = priorityLevelToLabel(priorityLevel);1306 logRenderStarted(label);1307 }1308 }1309 do {1310 try {1311 workLoopSync();1312 break;1313 } catch (thrownValue) {1314 handleError(root, thrownValue);1315 }1316 } while (true);1317 resetContextDependencies();1318 if (enableSchedulerTracing) {1319 popInteractions(((prevInteractions: any): Set<Interaction>));1320 }1321 executionContext = prevExecutionContext;1322 popDispatcher(prevDispatcher);1323 if (workInProgress !== null) {1324 // This is a sync render, so we should have finished the whole tree.1325 invariant(1326 false,1327 'Cannot commit an incomplete root. This error is likely caused by a ' +1328 'bug in React. Please file an issue.',1329 );1330 }1331 if (__DEV__) {1332 if (enableDebugTracing) {1333 logRenderStopped();1334 }1335 }1336 // Set this to null to indicate there's no in-progress render.1337 workInProgressRoot = null;1338 return workInProgressRootExitStatus;1339}1340// The work loop is an extremely hot path. Tell Closure not to inline it.1341/** @noinline */1342function workLoopSync() {1343 // Already timed out, so perform work without checking if we need to yield.1344 while (workInProgress !== null) {1345 performUnitOfWork(workInProgress);1346 }1347}1348function renderRootConcurrent(root, expirationTime) {1349 const prevExecutionContext = executionContext;1350 executionContext |= RenderContext;1351 const prevDispatcher = pushDispatcher(root);1352 // If the root or expiration time have changed, throw out the existing stack1353 // and prepare a fresh one. Otherwise we'll continue where we left off.1354 if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) {1355 prepareFreshStack(root, expirationTime);1356 startWorkOnPendingInteractions(root, expirationTime);1357 }1358 const prevInteractions = pushInteractions(root);1359 if (__DEV__) {1360 if (enableDebugTracing) {1361 const priorityLevel = getCurrentPriorityLevel();1362 const label = priorityLevelToLabel(priorityLevel);1363 logRenderStarted(label);1364 }1365 }1366 do {1367 try {1368 workLoopConcurrent();1369 break;1370 } catch (thrownValue) {1371 handleError(root, thrownValue);1372 }1373 } while (true);1374 resetContextDependencies();1375 if (enableSchedulerTracing) {1376 popInteractions(((prevInteractions: any): Set<Interaction>));1377 }1378 popDispatcher(prevDispatcher);1379 executionContext = prevExecutionContext;1380 if (__DEV__) {1381 if (enableDebugTracing) {1382 logRenderStopped();1383 }1384 }1385 // Check if the tree has completed.1386 if (workInProgress !== null) {1387 // Still work remaining.1388 return RootIncomplete;1389 } else {1390 // Completed the tree.1391 // Set this to null to indicate there's no in-progress render.1392 workInProgressRoot = null;1393 // Return the final exit status.1394 return workInProgressRootExitStatus;1395 }1396}1397/** @noinline */1398function workLoopConcurrent() {1399 // Perform work until Scheduler asks us to yield1400 while (workInProgress !== null && !shouldYield()) {1401 performUnitOfWork(workInProgress);1402 }1403}1404function performUnitOfWork(unitOfWork: Fiber): void {1405 // The current, flushed, state of this fiber is the alternate. Ideally1406 // nothing should rely on this, but relying on it here means that we don't1407 // need an additional field on the work in progress.1408 const current = unitOfWork.alternate;1409 setCurrentDebugFiberInDEV(unitOfWork);1410 let next;1411 if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {1412 startProfilerTimer(unitOfWork);1413 next = beginWork(current, unitOfWork, renderExpirationTime);1414 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);1415 } else {1416 next = beginWork(current, unitOfWork, renderExpirationTime);1417 }1418 resetCurrentDebugFiberInDEV();1419 unitOfWork.memoizedProps = unitOfWork.pendingProps;1420 if (next === null) {1421 // If this doesn't spawn new work, complete the current work.1422 completeUnitOfWork(unitOfWork);1423 } else {1424 workInProgress = next;1425 }1426 ReactCurrentOwner.current = null;1427}1428function completeUnitOfWork(unitOfWork: Fiber): void {1429 // Attempt to complete the current unit of work, then move to the next1430 // sibling. If there are no more siblings, return to the parent fiber.1431 let completedWork = unitOfWork;1432 do {1433 // The current, flushed, state of this fiber is the alternate. Ideally1434 // nothing should rely on this, but relying on it here means that we don't1435 // need an additional field on the work in progress.1436 const current = completedWork.alternate;1437 const returnFiber = completedWork.return;1438 // Check if the work completed or if something threw.1439 if ((completedWork.effectTag & Incomplete) === NoEffect) {1440 setCurrentDebugFiberInDEV(completedWork);1441 let next;1442 if (1443 !enableProfilerTimer ||1444 (completedWork.mode & ProfileMode) === NoMode1445 ) {1446 next = completeWork(current, completedWork, renderExpirationTime);1447 } else {1448 startProfilerTimer(completedWork);1449 next = completeWork(current, completedWork, renderExpirationTime);1450 // Update render duration assuming we didn't error.1451 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1452 }1453 resetCurrentDebugFiberInDEV();1454 resetChildExpirationTime(completedWork);1455 if (next !== null) {1456 // Completing this fiber spawned new work. Work on that next.1457 workInProgress = next;1458 return;1459 }1460 if (1461 returnFiber !== null &&1462 // Do not append effects to parents if a sibling failed to complete1463 (returnFiber.effectTag & Incomplete) === NoEffect1464 ) {1465 // Append all the effects of the subtree and this fiber onto the effect1466 // list of the parent. The completion order of the children affects the1467 // side-effect order.1468 if (returnFiber.firstEffect === null) {1469 returnFiber.firstEffect = completedWork.firstEffect;1470 }1471 if (completedWork.lastEffect !== null) {1472 if (returnFiber.lastEffect !== null) {1473 returnFiber.lastEffect.nextEffect = completedWork.firstEffect;1474 }1475 returnFiber.lastEffect = completedWork.lastEffect;1476 }1477 // If this fiber had side-effects, we append it AFTER the children's1478 // side-effects. We can perform certain side-effects earlier if needed,1479 // by doing multiple passes over the effect list. We don't want to1480 // schedule our own side-effect on our own list because if end up1481 // reusing children we'll schedule this effect onto itself since we're1482 // at the end.1483 const effectTag = completedWork.effectTag;1484 // Skip both NoWork and PerformedWork tags when creating the effect1485 // list. PerformedWork effect is read by React DevTools but shouldn't be1486 // committed.1487 if (effectTag > PerformedWork) {1488 if (returnFiber.lastEffect !== null) {1489 returnFiber.lastEffect.nextEffect = completedWork;1490 } else {1491 returnFiber.firstEffect = completedWork;1492 }1493 returnFiber.lastEffect = completedWork;1494 }1495 }1496 } else {1497 // This fiber did not complete because something threw. Pop values off1498 // the stack without entering the complete phase. If this is a boundary,1499 // capture values if possible.1500 const next = unwindWork(completedWork, renderExpirationTime);1501 // Because this fiber did not complete, don't reset its expiration time.1502 if (1503 enableProfilerTimer &&1504 (completedWork.mode & ProfileMode) !== NoMode1505 ) {1506 // Record the render duration for the fiber that errored.1507 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1508 // Include the time spent working on failed children before continuing.1509 let actualDuration = completedWork.actualDuration;1510 let child = completedWork.child;1511 while (child !== null) {1512 actualDuration += child.actualDuration;1513 child = child.sibling;1514 }1515 completedWork.actualDuration = actualDuration;1516 }1517 if (next !== null) {1518 // If completing this work spawned new work, do that next. We'll come1519 // back here again.1520 // Since we're restarting, remove anything that is not a host effect1521 // from the effect tag.1522 next.effectTag &= HostEffectMask;1523 workInProgress = next;1524 return;1525 }1526 if (returnFiber !== null) {1527 // Mark the parent fiber as incomplete and clear its effect list.1528 returnFiber.firstEffect = returnFiber.lastEffect = null;1529 returnFiber.effectTag |= Incomplete;1530 }1531 }1532 const siblingFiber = completedWork.sibling;1533 if (siblingFiber !== null) {1534 // If there is more work to do in this returnFiber, do that next.1535 workInProgress = siblingFiber;1536 return;1537 }1538 // Otherwise, return to the parent1539 completedWork = returnFiber;1540 // Update the next thing we're working on in case something throws.1541 workInProgress = completedWork;1542 } while (completedWork !== null);1543 // We've reached the root.1544 if (workInProgressRootExitStatus === RootIncomplete) {1545 workInProgressRootExitStatus = RootCompleted;1546 }1547}1548function getRemainingExpirationTime(fiber: Fiber) {1549 const updateExpirationTime = fiber.expirationTime;1550 const childExpirationTime = fiber.childExpirationTime;1551 return updateExpirationTime > childExpirationTime1552 ? updateExpirationTime1553 : childExpirationTime;1554}1555function resetChildExpirationTime(completedWork: Fiber) {1556 if (1557 renderExpirationTime !== Never &&1558 completedWork.childExpirationTime === Never1559 ) {1560 // The children of this component are hidden. Don't bubble their1561 // expiration times.1562 return;1563 }1564 let newChildExpirationTime = NoWork;1565 // Bubble up the earliest expiration time.1566 if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {1567 // In profiling mode, resetChildExpirationTime is also used to reset1568 // profiler durations.1569 let actualDuration = completedWork.actualDuration;1570 let treeBaseDuration = completedWork.selfBaseDuration;1571 // When a fiber is cloned, its actualDuration is reset to 0. This value will1572 // only be updated if work is done on the fiber (i.e. it doesn't bailout).1573 // When work is done, it should bubble to the parent's actualDuration. If1574 // the fiber has not been cloned though, (meaning no work was done), then1575 // this value will reflect the amount of time spent working on a previous1576 // render. In that case it should not bubble. We determine whether it was1577 // cloned by comparing the child pointer.1578 const shouldBubbleActualDurations =1579 completedWork.alternate === null ||1580 completedWork.child !== completedWork.alternate.child;1581 let child = completedWork.child;1582 while (child !== null) {1583 const childUpdateExpirationTime = child.expirationTime;1584 const childChildExpirationTime = child.childExpirationTime;1585 if (childUpdateExpirationTime > newChildExpirationTime) {1586 newChildExpirationTime = childUpdateExpirationTime;1587 }1588 if (childChildExpirationTime > newChildExpirationTime) {1589 newChildExpirationTime = childChildExpirationTime;1590 }1591 if (shouldBubbleActualDurations) {1592 actualDuration += child.actualDuration;1593 }1594 treeBaseDuration += child.treeBaseDuration;1595 child = child.sibling;1596 }1597 completedWork.actualDuration = actualDuration;1598 completedWork.treeBaseDuration = treeBaseDuration;1599 } else {1600 let child = completedWork.child;1601 while (child !== null) {1602 const childUpdateExpirationTime = child.expirationTime;1603 const childChildExpirationTime = child.childExpirationTime;1604 if (childUpdateExpirationTime > newChildExpirationTime) {1605 newChildExpirationTime = childUpdateExpirationTime;1606 }1607 if (childChildExpirationTime > newChildExpirationTime) {1608 newChildExpirationTime = childChildExpirationTime;1609 }1610 child = child.sibling;1611 }1612 }1613 completedWork.childExpirationTime = newChildExpirationTime;1614}1615function commitRoot(root) {1616 const renderPriorityLevel = getCurrentPriorityLevel();1617 runWithPriority(1618 ImmediatePriority,1619 commitRootImpl.bind(null, root, renderPriorityLevel),1620 );1621 return null;1622}1623function commitRootImpl(root, renderPriorityLevel) {1624 if (__DEV__) {1625 if (enableDebugTracing) {1626 const label = priorityLevelToLabel(renderPriorityLevel);1627 logCommitStarted(label);1628 }1629 }1630 do {1631 // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1632 // means `flushPassiveEffects` will sometimes result in additional1633 // passive effects. So we need to keep flushing in a loop until there are1634 // no more pending effects.1635 // TODO: Might be better if `flushPassiveEffects` did not automatically1636 // flush synchronous work at the end, to avoid factoring hazards like this.1637 flushPassiveEffects();1638 } while (rootWithPendingPassiveEffects !== null);1639 flushRenderPhaseStrictModeWarningsInDEV();1640 invariant(1641 (executionContext & (RenderContext | CommitContext)) === NoContext,1642 'Should not already be working.',1643 );1644 const finishedWork = root.finishedWork;1645 const expirationTime = root.finishedExpirationTime;1646 if (finishedWork === null) {1647 if (__DEV__) {1648 if (enableDebugTracing) {1649 logCommitStopped();1650 }1651 }1652 return null;1653 }1654 root.finishedWork = null;1655 root.finishedExpirationTime = NoWork;1656 invariant(1657 finishedWork !== root.current,1658 'Cannot commit the same tree as before. This error is likely caused by ' +1659 'a bug in React. Please file an issue.',1660 );1661 // commitRoot never returns a continuation; it always finishes synchronously.1662 // So we can clear these now to allow a new callback to be scheduled.1663 root.callbackNode = null;1664 root.callbackExpirationTime = NoWork;1665 root.callbackPriority = NoPriority;1666 // Update the first and last pending times on this root. The new first1667 // pending time is whatever is left on the root fiber.1668 const remainingExpirationTimeBeforeCommit = getRemainingExpirationTime(1669 finishedWork,1670 );1671 markRootFinishedAtTime(1672 root,1673 expirationTime,1674 remainingExpirationTimeBeforeCommit,1675 );1676 // Clear already finished discrete updates in case that a later call of1677 // `flushDiscreteUpdates` starts a useless render pass which may cancels1678 // a scheduled timeout.1679 if (rootsWithPendingDiscreteUpdates !== null) {1680 const lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);1681 if (1682 lastDiscreteTime !== undefined &&1683 remainingExpirationTimeBeforeCommit < lastDiscreteTime1684 ) {1685 rootsWithPendingDiscreteUpdates.delete(root);1686 }1687 }1688 if (root === workInProgressRoot) {1689 // We can reset these now that they are finished.1690 workInProgressRoot = null;1691 workInProgress = null;1692 renderExpirationTime = NoWork;1693 } else {1694 // This indicates that the last root we worked on is not the same one that1695 // we're committing now. This most commonly happens when a suspended root1696 // times out.1697 }1698 // Get the list of effects.1699 let firstEffect;1700 if (finishedWork.effectTag > PerformedWork) {1701 // A fiber's effect list consists only of its children, not itself. So if1702 // the root has an effect, we need to add it to the end of the list. The1703 // resulting list is the set that would belong to the root's parent, if it1704 // had one; that is, all the effects in the tree including the root.1705 if (finishedWork.lastEffect !== null) {1706 finishedWork.lastEffect.nextEffect = finishedWork;1707 firstEffect = finishedWork.firstEffect;1708 } else {1709 firstEffect = finishedWork;1710 }1711 } else {1712 // There is no effect on the root.1713 firstEffect = finishedWork.firstEffect;1714 }1715 if (firstEffect !== null) {1716 const prevExecutionContext = executionContext;1717 executionContext |= CommitContext;1718 const prevInteractions = pushInteractions(root);1719 // Reset this to null before calling lifecycles1720 ReactCurrentOwner.current = null;1721 // The commit phase is broken into several sub-phases. We do a separate pass1722 // of the effect list for each phase: all mutation effects come before all1723 // layout effects, and so on.1724 // The first phase a "before mutation" phase. We use this phase to read the1725 // state of the host tree right before we mutate it. This is where1726 // getSnapshotBeforeUpdate is called.1727 prepareForCommit(root.containerInfo);1728 nextEffect = firstEffect;1729 do {1730 if (__DEV__) {1731 invokeGuardedCallback(null, commitBeforeMutationEffects, null);1732 if (hasCaughtError()) {1733 invariant(nextEffect !== null, 'Should be working on an effect.');1734 const error = clearCaughtError();1735 captureCommitPhaseError(nextEffect, error);1736 nextEffect = nextEffect.nextEffect;1737 }1738 } else {1739 try {1740 commitBeforeMutationEffects();1741 } catch (error) {1742 invariant(nextEffect !== null, 'Should be working on an effect.');1743 captureCommitPhaseError(nextEffect, error);1744 nextEffect = nextEffect.nextEffect;1745 }1746 }1747 } while (nextEffect !== null);1748 if (enableProfilerTimer) {1749 // Mark the current commit time to be shared by all Profilers in this1750 // batch. This enables them to be grouped later.1751 recordCommitTime();1752 }1753 // The next phase is the mutation phase, where we mutate the host tree.1754 nextEffect = firstEffect;1755 do {1756 if (__DEV__) {1757 invokeGuardedCallback(1758 null,1759 commitMutationEffects,1760 null,1761 root,1762 renderPriorityLevel,1763 );1764 if (hasCaughtError()) {1765 invariant(nextEffect !== null, 'Should be working on an effect.');1766 const error = clearCaughtError();1767 captureCommitPhaseError(nextEffect, error);1768 nextEffect = nextEffect.nextEffect;1769 }1770 } else {1771 try {1772 commitMutationEffects(root, renderPriorityLevel);1773 } catch (error) {1774 invariant(nextEffect !== null, 'Should be working on an effect.');1775 captureCommitPhaseError(nextEffect, error);1776 nextEffect = nextEffect.nextEffect;1777 }1778 }1779 } while (nextEffect !== null);1780 resetAfterCommit(root.containerInfo);1781 // The work-in-progress tree is now the current tree. This must come after1782 // the mutation phase, so that the previous tree is still current during1783 // componentWillUnmount, but before the layout phase, so that the finished1784 // work is current during componentDidMount/Update.1785 root.current = finishedWork;1786 // The next phase is the layout phase, where we call effects that read1787 // the host tree after it's been mutated. The idiomatic use case for this is1788 // layout, but class component lifecycles also fire here for legacy reasons.1789 nextEffect = firstEffect;1790 do {1791 if (__DEV__) {1792 invokeGuardedCallback(1793 null,1794 commitLayoutEffects,1795 null,1796 root,1797 expirationTime,1798 );1799 if (hasCaughtError()) {1800 invariant(nextEffect !== null, 'Should be working on an effect.');1801 const error = clearCaughtError();1802 captureCommitPhaseError(nextEffect, error);1803 nextEffect = nextEffect.nextEffect;1804 }1805 } else {1806 try {1807 commitLayoutEffects(root, expirationTime);1808 } catch (error) {1809 invariant(nextEffect !== null, 'Should be working on an effect.');1810 captureCommitPhaseError(nextEffect, error);1811 nextEffect = nextEffect.nextEffect;1812 }1813 }1814 } while (nextEffect !== null);1815 nextEffect = null;1816 // Tell Scheduler to yield at the end of the frame, so the browser has an1817 // opportunity to paint.1818 requestPaint();1819 if (enableSchedulerTracing) {1820 popInteractions(((prevInteractions: any): Set<Interaction>));1821 }1822 executionContext = prevExecutionContext;1823 } else {1824 // No effects.1825 root.current = finishedWork;1826 // Measure these anyway so the flamegraph explicitly shows that there were1827 // no effects.1828 // TODO: Maybe there's a better way to report this.1829 if (enableProfilerTimer) {1830 recordCommitTime();1831 }1832 }1833 const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1834 if (rootDoesHavePassiveEffects) {1835 // This commit has passive effects. Stash a reference to them. But don't1836 // schedule a callback until after flushing layout work.1837 rootDoesHavePassiveEffects = false;1838 rootWithPendingPassiveEffects = root;1839 pendingPassiveEffectsExpirationTime = expirationTime;1840 pendingPassiveEffectsRenderPriority = renderPriorityLevel;1841 } else {1842 // We are done with the effect chain at this point so let's clear the1843 // nextEffect pointers to assist with GC. If we have passive effects, we'll1844 // clear this in flushPassiveEffects.1845 nextEffect = firstEffect;1846 while (nextEffect !== null) {1847 const nextNextEffect = nextEffect.nextEffect;1848 nextEffect.nextEffect = null;1849 nextEffect = nextNextEffect;1850 }1851 }1852 // Check if there's remaining work on this root1853 const remainingExpirationTime = root.firstPendingTime;1854 if (remainingExpirationTime !== NoWork) {1855 if (enableSchedulerTracing) {1856 if (spawnedWorkDuringRender !== null) {1857 const expirationTimes = spawnedWorkDuringRender;1858 spawnedWorkDuringRender = null;1859 for (let i = 0; i < expirationTimes.length; i++) {1860 scheduleInteractions(1861 root,1862 expirationTimes[i],1863 root.memoizedInteractions,1864 );1865 }1866 }1867 schedulePendingInteractions(root, remainingExpirationTime);1868 }1869 } else {1870 // If there's no remaining work, we can clear the set of already failed1871 // error boundaries.1872 legacyErrorBoundariesThatAlreadyFailed = null;1873 }1874 if (enableSchedulerTracing) {1875 if (!rootDidHavePassiveEffects) {1876 // If there are no passive effects, then we can complete the pending interactions.1877 // Otherwise, we'll wait until after the passive effects are flushed.1878 // Wait to do this until after remaining work has been scheduled,1879 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1880 finishPendingInteractions(root, expirationTime);1881 }1882 }1883 if (remainingExpirationTime === Sync) {1884 // Count the number of times the root synchronously re-renders without1885 // finishing. If there are too many, it indicates an infinite update loop.1886 if (root === rootWithNestedUpdates) {1887 nestedUpdateCount++;1888 } else {1889 nestedUpdateCount = 0;1890 rootWithNestedUpdates = root;1891 }1892 } else {1893 nestedUpdateCount = 0;1894 }1895 onCommitRoot(finishedWork.stateNode, expirationTime);1896 // Always call this before exiting `commitRoot`, to ensure that any1897 // additional work on this root is scheduled.1898 ensureRootIsScheduled(root);1899 if (hasUncaughtError) {1900 hasUncaughtError = false;1901 const error = firstUncaughtError;1902 firstUncaughtError = null;1903 throw error;1904 }1905 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1906 if (__DEV__) {1907 if (enableDebugTracing) {1908 logCommitStopped();1909 }1910 }1911 // This is a legacy edge case. We just committed the initial mount of1912 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1913 // synchronously, but layout updates should be deferred until the end1914 // of the batch.1915 return null;1916 }1917 // If layout work was scheduled, flush it now.1918 flushSyncCallbackQueue();1919 if (__DEV__) {1920 if (enableDebugTracing) {1921 logCommitStopped();1922 }1923 }1924 return null;1925}1926function commitBeforeMutationEffects() {1927 while (nextEffect !== null) {1928 const effectTag = nextEffect.effectTag;1929 if ((effectTag & Snapshot) !== NoEffect) {1930 setCurrentDebugFiberInDEV(nextEffect);1931 const current = nextEffect.alternate;1932 commitBeforeMutationEffectOnFiber(current, nextEffect);1933 resetCurrentDebugFiberInDEV();1934 }1935 if ((effectTag & Passive) !== NoEffect) {1936 // If there are passive effects, schedule a callback to flush at1937 // the earliest opportunity.1938 if (!rootDoesHavePassiveEffects) {1939 rootDoesHavePassiveEffects = true;1940 scheduleCallback(NormalPriority, () => {1941 flushPassiveEffects();1942 return null;1943 });1944 }1945 }1946 nextEffect = nextEffect.nextEffect;1947 }1948}1949function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {1950 // TODO: Should probably move the bulk of this function to commitWork.1951 while (nextEffect !== null) {1952 setCurrentDebugFiberInDEV(nextEffect);1953 const effectTag = nextEffect.effectTag;1954 if (effectTag & ContentReset) {1955 commitResetTextContent(nextEffect);1956 }1957 if (effectTag & Ref) {1958 const current = nextEffect.alternate;1959 if (current !== null) {1960 commitDetachRef(current);1961 }1962 }1963 // The following switch statement is only concerned about placement,1964 // updates, and deletions. To avoid needing to add a case for every possible1965 // bitmap value, we remove the secondary effects from the effect tag and1966 // switch on that value.1967 const primaryEffectTag =1968 effectTag & (Placement | Update | Deletion | Hydrating);1969 switch (primaryEffectTag) {1970 case Placement: {1971 commitPlacement(nextEffect);1972 // Clear the "placement" from effect tag so that we know that this is1973 // inserted, before any life-cycles like componentDidMount gets called.1974 // TODO: findDOMNode doesn't rely on this any more but isMounted does1975 // and isMounted is deprecated anyway so we should be able to kill this.1976 nextEffect.effectTag &= ~Placement;1977 break;1978 }1979 case PlacementAndUpdate: {1980 // Placement1981 commitPlacement(nextEffect);1982 // Clear the "placement" from effect tag so that we know that this is1983 // inserted, before any life-cycles like componentDidMount gets called.1984 nextEffect.effectTag &= ~Placement;1985 // Update1986 const current = nextEffect.alternate;1987 commitWork(current, nextEffect);1988 break;1989 }1990 case Hydrating: {1991 nextEffect.effectTag &= ~Hydrating;1992 break;1993 }1994 case HydratingAndUpdate: {1995 nextEffect.effectTag &= ~Hydrating;1996 // Update1997 const current = nextEffect.alternate;1998 commitWork(current, nextEffect);1999 break;2000 }2001 case Update: {2002 const current = nextEffect.alternate;2003 commitWork(current, nextEffect);2004 break;2005 }2006 case Deletion: {2007 commitDeletion(root, nextEffect, renderPriorityLevel);2008 break;2009 }2010 }2011 resetCurrentDebugFiberInDEV();2012 nextEffect = nextEffect.nextEffect;2013 }2014}2015function commitLayoutEffects(2016 root: FiberRoot,2017 committedExpirationTime: ExpirationTime,2018) {2019 if (__DEV__) {2020 if (enableDebugTracing) {2021 const priorityLevel = getCurrentPriorityLevel();2022 const label = priorityLevelToLabel(priorityLevel);2023 logLayoutEffectsStarted(label);2024 }2025 }2026 // TODO: Should probably move the bulk of this function to commitWork.2027 while (nextEffect !== null) {2028 setCurrentDebugFiberInDEV(nextEffect);2029 const effectTag = nextEffect.effectTag;2030 if (effectTag & (Update | Callback)) {2031 const current = nextEffect.alternate;2032 commitLayoutEffectOnFiber(2033 root,2034 current,2035 nextEffect,2036 committedExpirationTime,2037 );2038 }2039 if (effectTag & Ref) {2040 commitAttachRef(nextEffect);2041 }2042 resetCurrentDebugFiberInDEV();2043 nextEffect = nextEffect.nextEffect;2044 }2045 if (__DEV__) {2046 if (enableDebugTracing) {2047 logLayoutEffectsStopped();2048 }2049 }2050}2051export function flushPassiveEffects() {2052 if (pendingPassiveEffectsRenderPriority !== NoPriority) {2053 const priorityLevel =2054 pendingPassiveEffectsRenderPriority > NormalPriority2055 ? NormalPriority2056 : pendingPassiveEffectsRenderPriority;2057 pendingPassiveEffectsRenderPriority = NoPriority;2058 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2059 }2060}2061export function enqueuePendingPassiveProfilerEffect(fiber: Fiber): void {2062 if (enableProfilerTimer && enableProfilerCommitHooks) {2063 pendingPassiveProfilerEffects.push(fiber);2064 if (!rootDoesHavePassiveEffects) {2065 rootDoesHavePassiveEffects = true;2066 scheduleCallback(NormalPriority, () => {2067 flushPassiveEffects();2068 return null;2069 });2070 }2071 }2072}2073export function enqueuePendingPassiveHookEffectMount(2074 fiber: Fiber,2075 effect: HookEffect,2076): void {2077 if (runAllPassiveEffectDestroysBeforeCreates) {2078 pendingPassiveHookEffectsMount.push(effect, fiber);2079 if (!rootDoesHavePassiveEffects) {2080 rootDoesHavePassiveEffects = true;2081 scheduleCallback(NormalPriority, () => {2082 flushPassiveEffects();2083 return null;2084 });2085 }2086 }2087}2088export function enqueuePendingPassiveHookEffectUnmount(2089 fiber: Fiber,2090 effect: HookEffect,2091): void {2092 if (runAllPassiveEffectDestroysBeforeCreates) {2093 pendingPassiveHookEffectsUnmount.push(effect, fiber);2094 if (__DEV__) {2095 if (deferPassiveEffectCleanupDuringUnmount) {2096 fiber.effectTag |= PassiveUnmountPendingDev;2097 const alternate = fiber.alternate;2098 if (alternate !== null) {2099 alternate.effectTag |= PassiveUnmountPendingDev;2100 }2101 }2102 }2103 if (!rootDoesHavePassiveEffects) {2104 rootDoesHavePassiveEffects = true;2105 scheduleCallback(NormalPriority, () => {2106 flushPassiveEffects();2107 return null;2108 });2109 }2110 }2111}2112function invokePassiveEffectCreate(effect: HookEffect): void {2113 const create = effect.create;2114 effect.destroy = create();2115}2116function flushPassiveEffectsImpl() {2117 if (rootWithPendingPassiveEffects === null) {2118 return false;2119 }2120 const root = rootWithPendingPassiveEffects;2121 const expirationTime = pendingPassiveEffectsExpirationTime;2122 rootWithPendingPassiveEffects = null;2123 pendingPassiveEffectsExpirationTime = NoWork;2124 invariant(2125 (executionContext & (RenderContext | CommitContext)) === NoContext,2126 'Cannot flush passive effects while already rendering.',2127 );2128 if (__DEV__) {2129 if (enableDebugTracing) {2130 const priorityLevel = getCurrentPriorityLevel();2131 const label = priorityLevelToLabel(priorityLevel);2132 logPassiveEffectsStarted(label);2133 }2134 }2135 if (__DEV__) {2136 isFlushingPassiveEffects = true;2137 }2138 const prevExecutionContext = executionContext;2139 executionContext |= CommitContext;2140 const prevInteractions = pushInteractions(root);2141 if (runAllPassiveEffectDestroysBeforeCreates) {2142 // It's important that ALL pending passive effect destroy functions are called2143 // before ANY passive effect create functions are called.2144 // Otherwise effects in sibling components might interfere with each other.2145 // e.g. a destroy function in one component may unintentionally override a ref2146 // value set by a create function in another component.2147 // Layout effects have the same constraint.2148 // First pass: Destroy stale passive effects.2149 const unmountEffects = pendingPassiveHookEffectsUnmount;2150 pendingPassiveHookEffectsUnmount = [];2151 for (let i = 0; i < unmountEffects.length; i += 2) {2152 const effect = ((unmountEffects[i]: any): HookEffect);2153 const fiber = ((unmountEffects[i + 1]: any): Fiber);2154 const destroy = effect.destroy;2155 effect.destroy = undefined;2156 if (__DEV__) {2157 if (deferPassiveEffectCleanupDuringUnmount) {2158 fiber.effectTag &= ~PassiveUnmountPendingDev;2159 const alternate = fiber.alternate;2160 if (alternate !== null) {2161 alternate.effectTag &= ~PassiveUnmountPendingDev;2162 }2163 }2164 }2165 if (typeof destroy === 'function') {2166 if (__DEV__) {2167 setCurrentDebugFiberInDEV(fiber);2168 if (2169 enableProfilerTimer &&2170 enableProfilerCommitHooks &&2171 fiber.mode & ProfileMode2172 ) {2173 startPassiveEffectTimer();2174 invokeGuardedCallback(null, destroy, null);2175 recordPassiveEffectDuration(fiber);2176 } else {2177 invokeGuardedCallback(null, destroy, null);2178 }2179 if (hasCaughtError()) {2180 invariant(fiber !== null, 'Should be working on an effect.');2181 const error = clearCaughtError();2182 captureCommitPhaseError(fiber, error);2183 }2184 resetCurrentDebugFiberInDEV();2185 } else {2186 try {2187 if (2188 enableProfilerTimer &&2189 enableProfilerCommitHooks &&2190 fiber.mode & ProfileMode2191 ) {2192 try {2193 startPassiveEffectTimer();2194 destroy();2195 } finally {2196 recordPassiveEffectDuration(fiber);2197 }2198 } else {2199 destroy();2200 }2201 } catch (error) {2202 invariant(fiber !== null, 'Should be working on an effect.');2203 captureCommitPhaseError(fiber, error);2204 }2205 }2206 }2207 }2208 // Second pass: Create new passive effects.2209 const mountEffects = pendingPassiveHookEffectsMount;2210 pendingPassiveHookEffectsMount = [];2211 for (let i = 0; i < mountEffects.length; i += 2) {2212 const effect = ((mountEffects[i]: any): HookEffect);2213 const fiber = ((mountEffects[i + 1]: any): Fiber);2214 if (__DEV__) {2215 setCurrentDebugFiberInDEV(fiber);2216 if (2217 enableProfilerTimer &&2218 enableProfilerCommitHooks &&2219 fiber.mode & ProfileMode2220 ) {2221 startPassiveEffectTimer();2222 invokeGuardedCallback(null, invokePassiveEffectCreate, null, effect);2223 recordPassiveEffectDuration(fiber);2224 } else {2225 invokeGuardedCallback(null, invokePassiveEffectCreate, null, effect);2226 }2227 if (hasCaughtError()) {2228 invariant(fiber !== null, 'Should be working on an effect.');2229 const error = clearCaughtError();2230 captureCommitPhaseError(fiber, error);2231 }2232 resetCurrentDebugFiberInDEV();2233 } else {2234 try {2235 const create = effect.create;2236 if (2237 enableProfilerTimer &&2238 enableProfilerCommitHooks &&2239 fiber.mode & ProfileMode2240 ) {2241 try {2242 startPassiveEffectTimer();2243 effect.destroy = create();2244 } finally {2245 recordPassiveEffectDuration(fiber);2246 }2247 } else {2248 effect.destroy = create();2249 }2250 } catch (error) {2251 invariant(fiber !== null, 'Should be working on an effect.');2252 captureCommitPhaseError(fiber, error);2253 }2254 }2255 }2256 }2257 // Note: This currently assumes there are no passive effects on the root fiber2258 // because the root is not part of its own effect list.2259 // This could change in the future.2260 let effect = root.current.firstEffect;2261 while (effect !== null) {2262 // We do this work above if this flag is enabled, so we shouldn't be2263 // doing it here.2264 if (!runAllPassiveEffectDestroysBeforeCreates) {2265 if (__DEV__) {2266 setCurrentDebugFiberInDEV(effect);2267 invokeGuardedCallback(null, commitPassiveHookEffects, null, effect);2268 if (hasCaughtError()) {2269 invariant(effect !== null, 'Should be working on an effect.');2270 const error = clearCaughtError();2271 captureCommitPhaseError(effect, error);2272 }2273 resetCurrentDebugFiberInDEV();2274 } else {2275 try {2276 commitPassiveHookEffects(effect);2277 } catch (error) {2278 invariant(effect !== null, 'Should be working on an effect.');2279 captureCommitPhaseError(effect, error);2280 }2281 }2282 }2283 const nextNextEffect = effect.nextEffect;2284 // Remove nextEffect pointer to assist GC2285 effect.nextEffect = null;2286 effect = nextNextEffect;2287 }2288 if (enableProfilerTimer && enableProfilerCommitHooks) {2289 const profilerEffects = pendingPassiveProfilerEffects;2290 pendingPassiveProfilerEffects = [];2291 for (let i = 0; i < profilerEffects.length; i++) {2292 const fiber = ((profilerEffects[i]: any): Fiber);2293 commitPassiveEffectDurations(root, fiber);2294 }2295 }2296 if (enableSchedulerTracing) {2297 popInteractions(((prevInteractions: any): Set<Interaction>));2298 finishPendingInteractions(root, expirationTime);2299 }2300 if (__DEV__) {2301 isFlushingPassiveEffects = false;2302 }2303 if (__DEV__) {2304 if (enableDebugTracing) {2305 logPassiveEffectsStopped();2306 }2307 }2308 executionContext = prevExecutionContext;2309 flushSyncCallbackQueue();2310 // If additional passive effects were scheduled, increment a counter. If this2311 // exceeds the limit, we'll fire a warning.2312 nestedPassiveUpdateCount =2313 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;2314 return true;2315}2316export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {2317 return (2318 legacyErrorBoundariesThatAlreadyFailed !== null &&2319 legacyErrorBoundariesThatAlreadyFailed.has(instance)2320 );2321}2322export function markLegacyErrorBoundaryAsFailed(instance: mixed) {2323 if (legacyErrorBoundariesThatAlreadyFailed === null) {2324 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);2325 } else {2326 legacyErrorBoundariesThatAlreadyFailed.add(instance);2327 }2328}2329function prepareToThrowUncaughtError(error: mixed) {2330 if (!hasUncaughtError) {2331 hasUncaughtError = true;2332 firstUncaughtError = error;2333 }2334}2335export const onUncaughtError = prepareToThrowUncaughtError;2336function captureCommitPhaseErrorOnRoot(2337 rootFiber: Fiber,2338 sourceFiber: Fiber,2339 error: mixed,2340) {2341 const errorInfo = createCapturedValue(error, sourceFiber);2342 const update = createRootErrorUpdate(rootFiber, errorInfo, Sync);2343 enqueueUpdate(rootFiber, update);2344 const root = markUpdateTimeFromFiberToRoot(rootFiber, Sync);2345 if (root !== null) {2346 ensureRootIsScheduled(root);2347 schedulePendingInteractions(root, Sync);2348 }2349}2350export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {2351 if (sourceFiber.tag === HostRoot) {2352 // Error was thrown at the root. There is no parent, so the root2353 // itself should capture it.2354 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);2355 return;2356 }2357 let fiber = sourceFiber.return;2358 while (fiber !== null) {2359 if (fiber.tag === HostRoot) {2360 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);2361 return;2362 } else if (fiber.tag === ClassComponent) {2363 const ctor = fiber.type;2364 const instance = fiber.stateNode;2365 if (2366 typeof ctor.getDerivedStateFromError === 'function' ||2367 (typeof instance.componentDidCatch === 'function' &&2368 !isAlreadyFailedLegacyErrorBoundary(instance))2369 ) {2370 const errorInfo = createCapturedValue(error, sourceFiber);2371 const update = createClassErrorUpdate(2372 fiber,2373 errorInfo,2374 // TODO: This is always sync2375 Sync,2376 );2377 enqueueUpdate(fiber, update);2378 const root = markUpdateTimeFromFiberToRoot(fiber, Sync);2379 if (root !== null) {2380 ensureRootIsScheduled(root);2381 schedulePendingInteractions(root, Sync);2382 }2383 return;2384 }2385 }2386 fiber = fiber.return;2387 }2388}2389export function pingSuspendedRoot(2390 root: FiberRoot,2391 wakeable: Wakeable,2392 suspendedTime: ExpirationTime,2393) {2394 const pingCache = root.pingCache;2395 if (pingCache !== null) {2396 // The wakeable resolved, so we no longer need to memoize, because it will2397 // never be thrown again.2398 pingCache.delete(wakeable);2399 }2400 if (workInProgressRoot === root && renderExpirationTime === suspendedTime) {2401 // Received a ping at the same priority level at which we're currently2402 // rendering. We might want to restart this render. This should mirror2403 // the logic of whether or not a root suspends once it completes.2404 // TODO: If we're rendering sync either due to Sync, Batched or expired,2405 // we should probably never restart.2406 // If we're suspended with delay, we'll always suspend so we can always2407 // restart. If we're suspended without any updates, it might be a retry.2408 // If it's early in the retry we can restart. We can't know for sure2409 // whether we'll eventually process an update during this render pass,2410 // but it's somewhat unlikely that we get to a ping before that, since2411 // getting to the root most update is usually very fast.2412 if (2413 workInProgressRootExitStatus === RootSuspendedWithDelay ||2414 (workInProgressRootExitStatus === RootSuspended &&2415 workInProgressRootLatestProcessedEventTime === Sync &&2416 now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)2417 ) {2418 // Restart from the root. Don't need to schedule a ping because2419 // we're already working on this tree.2420 prepareFreshStack(root, renderExpirationTime);2421 } else {2422 // Even though we can't restart right now, we might get an2423 // opportunity later. So we mark this render as having a ping.2424 workInProgressRootHasPendingPing = true;2425 }2426 return;2427 }2428 if (!isRootSuspendedAtTime(root, suspendedTime)) {2429 // The root is no longer suspended at this time.2430 return;2431 }2432 const lastPingedTime = root.lastPingedTime;2433 if (lastPingedTime !== NoWork && lastPingedTime < suspendedTime) {2434 // There's already a lower priority ping scheduled.2435 return;2436 }2437 // Mark the time at which this ping was scheduled.2438 root.lastPingedTime = suspendedTime;2439 ensureRootIsScheduled(root);2440 schedulePendingInteractions(root, suspendedTime);2441}2442function retryTimedOutBoundary(2443 boundaryFiber: Fiber,2444 retryTime: ExpirationTime,2445) {2446 // The boundary fiber (a Suspense component or SuspenseList component)2447 // previously was rendered in its fallback state. One of the promises that2448 // suspended it has resolved, which means at least part of the tree was2449 // likely unblocked. Try rendering again, at a new expiration time.2450 if (retryTime === NoWork) {2451 const suspenseConfig = null; // Retries don't carry over the already committed update.2452 const currentTime = requestCurrentTimeForUpdate();2453 retryTime = computeExpirationForFiber(2454 currentTime,2455 boundaryFiber,2456 suspenseConfig,2457 );2458 }2459 // TODO: Special case idle priority?2460 const root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime);2461 if (root !== null) {2462 ensureRootIsScheduled(root);2463 schedulePendingInteractions(root, retryTime);2464 }2465}2466export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {2467 const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2468 let retryTime = NoWork;2469 if (suspenseState !== null) {2470 retryTime = suspenseState.retryTime;2471 }2472 retryTimedOutBoundary(boundaryFiber, retryTime);2473}2474export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {2475 let retryTime = NoWork; // Default2476 let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;2477 if (enableSuspenseServerRenderer) {2478 switch (boundaryFiber.tag) {2479 case SuspenseComponent:2480 retryCache = boundaryFiber.stateNode;2481 const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2482 if (suspenseState !== null) {2483 retryTime = suspenseState.retryTime;2484 }2485 break;2486 case SuspenseListComponent:2487 retryCache = boundaryFiber.stateNode;2488 break;2489 default:2490 invariant(2491 false,2492 'Pinged unknown suspense boundary type. ' +2493 'This is probably a bug in React.',2494 );2495 }2496 } else {2497 retryCache = boundaryFiber.stateNode;2498 }2499 if (retryCache !== null) {2500 // The wakeable resolved, so we no longer need to memoize, because it will2501 // never be thrown again.2502 retryCache.delete(wakeable);2503 }2504 retryTimedOutBoundary(boundaryFiber, retryTime);2505}2506// Computes the next Just Noticeable Difference (JND) boundary.2507// The theory is that a person can't tell the difference between small differences in time.2508// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable2509// difference in the experience. However, waiting for longer might mean that we can avoid2510// showing an intermediate loading state. The longer we have already waited, the harder it2511// is to tell small differences in time. Therefore, the longer we've already waited,2512// the longer we can wait additionally. At some point we have to give up though.2513// We pick a train model where the next boundary commits at a consistent schedule.2514// These particular numbers are vague estimates. We expect to adjust them based on research.2515function jnd(timeElapsed: number) {2516 return timeElapsed < 1202517 ? 1202518 : timeElapsed < 4802519 ? 4802520 : timeElapsed < 10802521 ? 10802522 : timeElapsed < 19202523 ? 19202524 : timeElapsed < 30002525 ? 30002526 : timeElapsed < 43202527 ? 43202528 : ceil(timeElapsed / 1960) * 1960;2529}2530function computeMsUntilSuspenseLoadingDelay(2531 mostRecentEventTime: ExpirationTime,2532 committedExpirationTime: ExpirationTime,2533 suspenseConfig: SuspenseConfig,2534) {2535 const busyMinDurationMs = (suspenseConfig.busyMinDurationMs: any) | 0;2536 if (busyMinDurationMs <= 0) {2537 return 0;2538 }2539 const busyDelayMs = (suspenseConfig.busyDelayMs: any) | 0;2540 // Compute the time until this render pass would expire.2541 const currentTimeMs: number = now();2542 const eventTimeMs: number = expirationTimeToMs(mostRecentEventTime);2543 const timeElapsed = currentTimeMs - eventTimeMs;2544 if (timeElapsed <= busyDelayMs) {2545 // If we haven't yet waited longer than the initial delay, we don't2546 // have to wait any additional time.2547 return 0;2548 }2549 const msUntilTimeout = busyDelayMs + busyMinDurationMs - timeElapsed;2550 // This is the value that is passed to `setTimeout`.2551 return msUntilTimeout;2552}2553function checkForNestedUpdates() {2554 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {2555 nestedUpdateCount = 0;2556 rootWithNestedUpdates = null;2557 invariant(2558 false,2559 'Maximum update depth exceeded. This can happen when a component ' +2560 'repeatedly calls setState inside componentWillUpdate or ' +2561 'componentDidUpdate. React limits the number of nested updates to ' +2562 'prevent infinite loops.',2563 );2564 }2565 if (__DEV__) {2566 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {2567 nestedPassiveUpdateCount = 0;2568 console.error(2569 'Maximum update depth exceeded. This can happen when a component ' +2570 "calls setState inside useEffect, but useEffect either doesn't " +2571 'have a dependency array, or one of the dependencies changes on ' +2572 'every render.',2573 );2574 }2575 }2576}2577function flushRenderPhaseStrictModeWarningsInDEV() {2578 if (__DEV__) {2579 ReactStrictModeWarnings.flushLegacyContextWarning();2580 if (warnAboutDeprecatedLifecycles) {2581 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();2582 }2583 }2584}2585let didWarnStateUpdateForUnmountedComponent: Set<string> | null = null;2586function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {2587 if (__DEV__) {2588 const tag = fiber.tag;2589 if (2590 tag !== HostRoot &&2591 tag !== ClassComponent &&2592 tag !== FunctionComponent &&2593 tag !== ForwardRef &&2594 tag !== MemoComponent &&2595 tag !== SimpleMemoComponent &&2596 tag !== Block2597 ) {2598 // Only warn for user-defined components, not internal ones like Suspense.2599 return;2600 }2601 if (2602 deferPassiveEffectCleanupDuringUnmount &&2603 runAllPassiveEffectDestroysBeforeCreates2604 ) {2605 // If there are pending passive effects unmounts for this Fiber,2606 // we can assume that they would have prevented this update.2607 if ((fiber.effectTag & PassiveUnmountPendingDev) !== NoEffect) {2608 return;2609 }2610 }2611 // We show the whole stack but dedupe on the top component's name because2612 // the problematic code almost always lies inside that component.2613 const componentName = getComponentName(fiber.type) || 'ReactComponent';2614 if (didWarnStateUpdateForUnmountedComponent !== null) {2615 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {2616 return;2617 }2618 didWarnStateUpdateForUnmountedComponent.add(componentName);2619 } else {2620 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);2621 }2622 if (isFlushingPassiveEffects) {2623 // Do not warn if we are currently flushing passive effects!2624 //2625 // React can't directly detect a memory leak, but there are some clues that warn about one.2626 // One of these clues is when an unmounted React component tries to update its state.2627 // For example, if a component forgets to remove an event listener when unmounting,2628 // that listener may be called later and try to update state,2629 // at which point React would warn about the potential leak.2630 //2631 // Warning signals are the most useful when they're strong.2632 // (So we should avoid false positive warnings.)2633 // Updating state from within an effect cleanup function is sometimes a necessary pattern, e.g.:2634 // 1. Updating an ancestor that a component had registered itself with on mount.2635 // 2. Resetting state when a component is hidden after going offscreen.2636 } else {2637 console.error(2638 "Can't perform a React state update on an unmounted component. This " +2639 'is a no-op, but it indicates a memory leak in your application. To ' +2640 'fix, cancel all subscriptions and asynchronous tasks in %s.%s',2641 tag === ClassComponent2642 ? 'the componentWillUnmount method'2643 : 'a useEffect cleanup function',2644 getStackByFiberInDevAndProd(fiber),2645 );2646 }2647 }2648}2649let beginWork;2650if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {2651 const dummyFiber = null;2652 beginWork = (current, unitOfWork, expirationTime) => {2653 // If a component throws an error, we replay it again in a synchronously2654 // dispatched event, so that the debugger will treat it as an uncaught2655 // error See ReactErrorUtils for more information.2656 // Before entering the begin phase, copy the work-in-progress onto a dummy2657 // fiber. If beginWork throws, we'll use this to reset the state.2658 const originalWorkInProgressCopy = assignFiberPropertiesInDEV(2659 dummyFiber,2660 unitOfWork,2661 );2662 try {2663 return originalBeginWork(current, unitOfWork, expirationTime);2664 } catch (originalError) {2665 if (2666 originalError !== null &&2667 typeof originalError === 'object' &&2668 typeof originalError.then === 'function'2669 ) {2670 // Don't replay promises. Treat everything else like an error.2671 throw originalError;2672 }2673 // Keep this code in sync with handleError; any changes here must have2674 // corresponding changes there.2675 resetContextDependencies();2676 resetHooksAfterThrow();2677 // Don't reset current debug fiber, since we're about to work on the2678 // same fiber again.2679 // Unwind the failed stack frame2680 unwindInterruptedWork(unitOfWork);2681 // Restore the original properties of the fiber.2682 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);2683 if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {2684 // Reset the profiler timer.2685 startProfilerTimer(unitOfWork);2686 }2687 // Run beginWork again.2688 invokeGuardedCallback(2689 null,2690 originalBeginWork,2691 null,2692 current,2693 unitOfWork,2694 expirationTime,2695 );2696 if (hasCaughtError()) {2697 const replayError = clearCaughtError();2698 // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.2699 // Rethrow this error instead of the original one.2700 throw replayError;2701 } else {2702 // This branch is reachable if the render phase is impure.2703 throw originalError;2704 }2705 }2706 };2707} else {2708 beginWork = originalBeginWork;2709}2710let didWarnAboutUpdateInRender = false;2711let didWarnAboutUpdateInRenderForAnotherComponent;2712if (__DEV__) {2713 didWarnAboutUpdateInRenderForAnotherComponent = new Set();2714}2715function warnAboutRenderPhaseUpdatesInDEV(fiber) {2716 if (__DEV__) {2717 if (2718 ReactCurrentDebugFiberIsRenderingInDEV &&2719 (executionContext & RenderContext) !== NoContext &&2720 !getIsUpdatingOpaqueValueInRenderPhaseInDEV()2721 ) {2722 switch (fiber.tag) {2723 case FunctionComponent:2724 case ForwardRef:2725 case SimpleMemoComponent: {2726 const renderingComponentName =2727 (workInProgress && getComponentName(workInProgress.type)) ||2728 'Unknown';2729 // Dedupe by the rendering component because it's the one that needs to be fixed.2730 const dedupeKey = renderingComponentName;2731 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {2732 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);2733 const setStateComponentName =2734 getComponentName(fiber.type) || 'Unknown';2735 console.error(2736 'Cannot update a component (`%s`) while rendering a ' +2737 'different component (`%s`). To locate the bad setState() call inside `%s`, ' +2738 'follow the stack trace as described in https://fb.me/setstate-in-render',2739 setStateComponentName,2740 renderingComponentName,2741 renderingComponentName,2742 );2743 }2744 break;2745 }2746 case ClassComponent: {2747 if (!didWarnAboutUpdateInRender) {2748 console.error(2749 'Cannot update during an existing state transition (such as ' +2750 'within `render`). Render methods should be a pure ' +2751 'function of props and state.',2752 );2753 didWarnAboutUpdateInRender = true;2754 }2755 break;2756 }2757 }2758 }2759 }2760}2761// a 'shared' variable that changes when act() opens/closes in tests.2762export const IsThisRendererActing = {current: (false: boolean)};2763export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {2764 if (__DEV__) {2765 if (2766 warnsIfNotActing === true &&2767 IsSomeRendererActing.current === true &&2768 IsThisRendererActing.current !== true2769 ) {2770 console.error(2771 "It looks like you're using the wrong act() around your test interactions.\n" +2772 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' +2773 '// for react-dom:\n' +2774 // Break up imports to avoid accidentally parsing them as dependencies.2775 'import {act} fr' +2776 "om 'react-dom/test-utils';\n" +2777 '// ...\n' +2778 'act(() => ...);\n\n' +2779 '// for react-test-renderer:\n' +2780 // Break up imports to avoid accidentally parsing them as dependencies.2781 'import TestRenderer fr' +2782 "om react-test-renderer';\n" +2783 'const {act} = TestRenderer;\n' +2784 '// ...\n' +2785 'act(() => ...);' +2786 '%s',2787 getStackByFiberInDevAndProd(fiber),2788 );2789 }2790 }2791}2792export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {2793 if (__DEV__) {2794 if (2795 warnsIfNotActing === true &&2796 (fiber.mode & StrictMode) !== NoMode &&2797 IsSomeRendererActing.current === false &&2798 IsThisRendererActing.current === false2799 ) {2800 console.error(2801 'An update to %s ran an effect, but was not wrapped in act(...).\n\n' +2802 'When testing, code that causes React state updates should be ' +2803 'wrapped into act(...):\n\n' +2804 'act(() => {\n' +2805 ' /* fire events that update state */\n' +2806 '});\n' +2807 '/* assert on the output */\n\n' +2808 "This ensures that you're testing the behavior the user would see " +2809 'in the browser.' +2810 ' Learn more at https://fb.me/react-wrap-tests-with-act' +2811 '%s',2812 getComponentName(fiber.type),2813 getStackByFiberInDevAndProd(fiber),2814 );2815 }2816 }2817}2818function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {2819 if (__DEV__) {2820 if (2821 warnsIfNotActing === true &&2822 executionContext === NoContext &&2823 IsSomeRendererActing.current === false &&2824 IsThisRendererActing.current === false2825 ) {2826 console.error(2827 'An update to %s inside a test was not wrapped in act(...).\n\n' +2828 'When testing, code that causes React state updates should be ' +2829 'wrapped into act(...):\n\n' +2830 'act(() => {\n' +2831 ' /* fire events that update state */\n' +2832 '});\n' +2833 '/* assert on the output */\n\n' +2834 "This ensures that you're testing the behavior the user would see " +2835 'in the browser.' +2836 ' Learn more at https://fb.me/react-wrap-tests-with-act' +2837 '%s',2838 getComponentName(fiber.type),2839 getStackByFiberInDevAndProd(fiber),2840 );2841 }2842 }2843}2844export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV;2845// In tests, we want to enforce a mocked scheduler.2846let didWarnAboutUnmockedScheduler = false;2847// TODO Before we release concurrent mode, revisit this and decide whether a mocked2848// scheduler is the actual recommendation. The alternative could be a testing build,2849// a new lib, or whatever; we dunno just yet. This message is for early adopters2850// to get their tests right.2851export function warnIfUnmockedScheduler(fiber: Fiber) {2852 if (__DEV__) {2853 if (2854 didWarnAboutUnmockedScheduler === false &&2855 Scheduler.unstable_flushAllWithoutAsserting === undefined2856 ) {2857 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) {2858 didWarnAboutUnmockedScheduler = true;2859 console.error(2860 'In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' +2861 'to guarantee consistent behaviour across tests and browsers. ' +2862 'For example, with jest: \n' +2863 // Break up requires to avoid accidentally parsing them as dependencies.2864 "jest.mock('scheduler', () => require" +2865 "('scheduler/unstable_mock'));\n\n" +2866 'For more info, visit https://fb.me/react-mock-scheduler',2867 );2868 } else if (warnAboutUnmockedScheduler === true) {2869 didWarnAboutUnmockedScheduler = true;2870 console.error(2871 'Starting from React v17, the "scheduler" module will need to be mocked ' +2872 'to guarantee consistent behaviour across tests and browsers. ' +2873 'For example, with jest: \n' +2874 // Break up requires to avoid accidentally parsing them as dependencies.2875 "jest.mock('scheduler', () => require" +2876 "('scheduler/unstable_mock'));\n\n" +2877 'For more info, visit https://fb.me/react-mock-scheduler',2878 );2879 }2880 }2881 }2882}2883function computeThreadID(root, expirationTime) {2884 // Interaction threads are unique per root and expiration time.2885 return expirationTime * 1000 + root.interactionThreadID;2886}2887export function markSpawnedWork(expirationTime: ExpirationTime) {2888 if (!enableSchedulerTracing) {2889 return;2890 }2891 if (spawnedWorkDuringRender === null) {2892 spawnedWorkDuringRender = [expirationTime];2893 } else {2894 spawnedWorkDuringRender.push(expirationTime);2895 }2896}2897function scheduleInteractions(root, expirationTime, interactions) {2898 if (!enableSchedulerTracing) {2899 return;2900 }2901 if (interactions.size > 0) {2902 const pendingInteractionMap = root.pendingInteractionMap;2903 const pendingInteractions = pendingInteractionMap.get(expirationTime);2904 if (pendingInteractions != null) {2905 interactions.forEach(interaction => {2906 if (!pendingInteractions.has(interaction)) {2907 // Update the pending async work count for previously unscheduled interaction.2908 interaction.__count++;2909 }2910 pendingInteractions.add(interaction);2911 });2912 } else {2913 pendingInteractionMap.set(expirationTime, new Set(interactions));2914 // Update the pending async work count for the current interactions.2915 interactions.forEach(interaction => {2916 interaction.__count++;2917 });2918 }2919 const subscriber = __subscriberRef.current;2920 if (subscriber !== null) {2921 const threadID = computeThreadID(root, expirationTime);2922 subscriber.onWorkScheduled(interactions, threadID);2923 }2924 }2925}2926function schedulePendingInteractions(root, expirationTime) {2927 // This is called when work is scheduled on a root.2928 // It associates the current interactions with the newly-scheduled expiration.2929 // They will be restored when that expiration is later committed.2930 if (!enableSchedulerTracing) {2931 return;2932 }2933 scheduleInteractions(root, expirationTime, __interactionsRef.current);2934}2935function startWorkOnPendingInteractions(root, expirationTime) {2936 // This is called when new work is started on a root.2937 if (!enableSchedulerTracing) {2938 return;2939 }2940 // Determine which interactions this batch of work currently includes, So that2941 // we can accurately attribute time spent working on it, And so that cascading2942 // work triggered during the render phase will be associated with it.2943 const interactions: Set<Interaction> = new Set();2944 root.pendingInteractionMap.forEach(2945 (scheduledInteractions, scheduledExpirationTime) => {2946 if (scheduledExpirationTime >= expirationTime) {2947 scheduledInteractions.forEach(interaction =>2948 interactions.add(interaction),2949 );2950 }2951 },2952 );2953 // Store the current set of interactions on the FiberRoot for a few reasons:2954 // We can re-use it in hot functions like performConcurrentWorkOnRoot()2955 // without having to recalculate it. We will also use it in commitWork() to2956 // pass to any Profiler onRender() hooks. This also provides DevTools with a2957 // way to access it when the onCommitRoot() hook is called.2958 root.memoizedInteractions = interactions;2959 if (interactions.size > 0) {2960 const subscriber = __subscriberRef.current;2961 if (subscriber !== null) {2962 const threadID = computeThreadID(root, expirationTime);2963 try {2964 subscriber.onWorkStarted(interactions, threadID);2965 } catch (error) {2966 // If the subscriber throws, rethrow it in a separate task2967 scheduleCallback(ImmediatePriority, () => {2968 throw error;2969 });2970 }2971 }2972 }2973}2974function finishPendingInteractions(root, committedExpirationTime) {2975 if (!enableSchedulerTracing) {2976 return;2977 }2978 const earliestRemainingTimeAfterCommit = root.firstPendingTime;2979 let subscriber;2980 try {2981 subscriber = __subscriberRef.current;2982 if (subscriber !== null && root.memoizedInteractions.size > 0) {2983 const threadID = computeThreadID(root, committedExpirationTime);2984 subscriber.onWorkStopped(root.memoizedInteractions, threadID);2985 }2986 } catch (error) {2987 // If the subscriber throws, rethrow it in a separate task2988 scheduleCallback(ImmediatePriority, () => {2989 throw error;2990 });2991 } finally {2992 // Clear completed interactions from the pending Map.2993 // Unless the render was suspended or cascading work was scheduled,2994 // In which caseâ leave pending interactions until the subsequent render.2995 const pendingInteractionMap = root.pendingInteractionMap;2996 pendingInteractionMap.forEach(2997 (scheduledInteractions, scheduledExpirationTime) => {2998 // Only decrement the pending interaction count if we're done.2999 // If there's still work at the current priority,3000 // That indicates that we are waiting for suspense data.3001 if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) {3002 pendingInteractionMap.delete(scheduledExpirationTime);3003 scheduledInteractions.forEach(interaction => {3004 interaction.__count--;3005 if (subscriber !== null && interaction.__count === 0) {3006 try {3007 subscriber.onInteractionScheduledWorkCompleted(interaction);3008 } catch (error) {3009 // If the subscriber throws, rethrow it in a separate task3010 scheduleCallback(ImmediatePriority, () => {3011 throw error;3012 });3013 }3014 }3015 });3016 }3017 },3018 );3019 }3020}3021// `act` testing API3022//3023// TODO: This is mostly a copy-paste from the legacy `act`, which does not have3024// access to the same internals that we do here. Some trade offs in the3025// implementation no longer make sense.3026let isFlushingAct = false;3027let isInsideThisAct = false;3028// TODO: Yes, this is confusing. See above comment. We'll refactor it.3029function shouldForceFlushFallbacksInDEV() {3030 if (!__DEV__) {3031 // Never force flush in production. This function should get stripped out.3032 return false;3033 }3034 // `IsThisRendererActing.current` is used by ReactTestUtils version of `act`.3035 if (IsThisRendererActing.current) {3036 // `isInsideAct` is only used by the reconciler implementation of `act`.3037 // We don't want to flush suspense fallbacks until the end.3038 return !isInsideThisAct;3039 }3040 // Flush callbacks at the end.3041 return isFlushingAct;3042}3043const flushMockScheduler = Scheduler.unstable_flushAllWithoutAsserting;...
ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js
...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()2143 // without having to recalculate it. We will also use it in commitWork() to2144 // pass to any Profiler onRender() hooks. This also provides DevTools with a2145 // way to access it when the onCommitRoot() hook is called.2146 root.memoizedInteractions = interactions;2147 if (interactions.size > 0) {2148 var subscriber = __subscriberRef.current;2149 if (subscriber !== null) {2150 var threadID = computeThreadID(root, lanes);2151 try {2152 subscriber.onWorkStarted(interactions, threadID);2153 } catch (error) {2154 // If the subscriber throws, rethrow it in a separate task2155 scheduleCallback(ImmediatePriority$1, function () {2156 throw error;2157 });2158 }2159 }2160 }2161 }2162 function finishPendingInteractions(root, committedLanes) {2163 var remainingLanesAfterCommit = root.pendingLanes;2164 var subscriber;2165 try {2166 subscriber = __subscriberRef.current;2167 if (subscriber !== null && root.memoizedInteractions.size > 0) {2168 // FIXME: More than one lane can finish in a single commit.2169 var threadID = computeThreadID(root, committedLanes);2170 subscriber.onWorkStopped(root.memoizedInteractions, threadID);2171 }2172 } catch (error) {2173 // If the subscriber throws, rethrow it in a separate task2174 scheduleCallback(ImmediatePriority$1, function () {2175 throw error;2176 });2177 } finally {2178 // Clear completed interactions from the pending Map.2179 // Unless the render was suspended or cascading work was scheduled,2180 // In which caseâ leave pending interactions until the subsequent render.2181 var pendingInteractionMap = root.pendingInteractionMap;2182 pendingInteractionMap.forEach(function (scheduledInteractions, lane) {2183 // Only decrement the pending interaction count if we're done.2184 // If there's still work at the current priority,2185 // That indicates that we are waiting for suspense data.2186 if (!includesSomeLane(remainingLanesAfterCommit, lane)) {2187 pendingInteractionMap.delete(lane);2188 scheduledInteractions.forEach(function (interaction) {2189 interaction.__count--;2190 if (subscriber !== null && interaction.__count === 0) {2191 try {2192 subscriber.onInteractionScheduledWorkCompleted(interaction);2193 } catch (error) {2194 // If the subscriber throws, rethrow it in a separate task2195 scheduleCallback(ImmediatePriority$1, function () {2196 throw error;2197 });2198 }2199 }2200 });2201 }2202 });2203 }2204 } // `act` testing API2205 function shouldForceFlushFallbacksInDEV() {2206 // Never force flush in production. This function should get stripped out.2207 return actingUpdatesScopeDepth > 0;2208 }2209 // so we can tell if any async act() calls try to run in parallel.2210 var actingUpdatesScopeDepth = 0;2211 function detachFiberAfterEffects(fiber) {2212 fiber.sibling = null;2213 fiber.stateNode = null;...
Using AI Code Generation
1const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2shouldForceFlushFallbacksInDEV();3const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');4shouldForceFlushFallbacksInDEV();5const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');6shouldForceFlushFallbacksInDEV();7const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');8shouldForceFlushFallbacksInDEV();9const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');10shouldForceFlushFallbacksInDEV();11const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');12shouldForceFlushFallbacksInDEV();13const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');14shouldForceFlushFallbacksInDEV();15const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');16shouldForceFlushFallbacksInDEV();17const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderSupplement');18shouldForceFlushFallbacksInDEV();19const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements
Using AI Code Generation
1const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');2const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');3const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');4const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');5const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');6const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');7const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');8const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');9const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');10const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');11const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/trace/common/traceEvents');
Using AI Code Generation
1const { shouldForceFlushFallbacksInDEV } = require('@playwright/test/lib/server/traceViewer/internalAPI');2shouldForceFlushFallbacksInDEV();3const { shouldForceFlushFallbacksInDEV } = require('@playwright/test/lib/server/traceViewer/internalAPI');4shouldForceFlushFallbacksInDEV();5const { shouldForceFlushFallbacksInDEV } = require('@playwright/test/lib/server/traceViewer/internalAPI');6shouldForceFlushFallbacksInDEV();7import { shouldForceFlushFallbacksInDEV } from '@playwright/test/lib/server/traceViewer/internalAPI';8shouldForceFlushFallbacksInDEV();9const { shouldForceFlushFallbacksInDEV } = require('@playwright/test/lib/server/traceViewer/internalAPI');10shouldForceFlushFallbacksInDEV();11import { shouldForceFlushFallbacksInDEV } from '@playwright/test/lib/server/traceViewer/internalAPI';12shouldForceFlushFallbacksInDEV();13import { shouldForceFlushFallbacksInDEV } from '@playwright/test/lib/server/traceViewer/internalAPI';14shouldForceFlushFallbacksInDEV();
Using AI Code Generation
1const {shouldForceFlushFallbacksInDEV} = require('playwright/lib/server/supplements/recorder/recorderSupplement');2console.log(shouldForceFlushFallbacksInDEV());3module.exports = {4 use: {5 viewport: { width: 1280, height: 720 },6 _recorder: {7 },8 },9};10"scripts": {11}
Using AI Code Generation
1const { chromium } = require('playwright');2const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/supplements/recorder/recorderApp');3const browser = await chromium.launch();4const context = await browser.newContext();5const page = await context.newPage();6await page.click('button');7await shouldForceFlushFallbacksInDEV(page);8browser.close();
Using AI Code Generation
1const { shouldForceFlushFallbacksInDEV } = require('playwright/lib/server/frames');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const frame = page.mainFrame();8 const shouldForceFlush = shouldForceFlushFallbacksInDEV();9 console.log(shouldForceFlush);10 await browser.close();11})();
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!!