How to use shouldForceFlushFallbacksInDEV method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberWorkLoop.new.js

Source:ReactFiberWorkLoop.new.js Github

copy

Full Screen

...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;...

Full Screen

Full Screen

ReactFiberWorkLoop.old.js

Source:ReactFiberWorkLoop.old.js Github

copy

Full Screen

...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;...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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');

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Using AI Code Generation

copy

Full Screen

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}

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Playwright tutorial

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.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

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

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful