import {REACT_STRICT_MODE_TYPE} from 'shared/ReactSymbols';
import type {Wakeable, Thenable} from 'shared/ReactTypes';
import type {Fiber, FiberRoot} from './ReactInternalTypes';
import type {Lanes, Lane} from './ReactFiberLane';
import type {SuspenseState} from './ReactFiberSuspenseComponent';
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
import type {EventPriority} from './ReactEventPriorities';
import type {
PendingTransitionCallbacks,
PendingBoundaries,
Transition,
TransitionAbort,
} from './ReactFiberTracingMarkerComponent';
import type {OffscreenInstance} from './ReactFiberActivityComponent';
import type {Resource} from './ReactFiberConfig';
import {
enableCreateEventHandleAPI,
enableProfilerTimer,
enableProfilerCommitHooks,
enableProfilerNestedUpdatePhase,
enableDebugTracing,
enableSchedulingProfiler,
enableUpdaterTracking,
enableCache,
enableTransitionTracing,
useModernStrictMode,
disableLegacyContext,
alwaysThrottleRetries,
enableInfiniteRenderLoopDetection,
disableLegacyMode,
disableDefaultPropsExceptForClasses,
disableStringRefs,
enableSiblingPrerendering,
enableComponentPerformanceTrack,
} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import is from 'shared/objectIs';
import {
scheduleCallback as Scheduler_scheduleCallback,
shouldYield,
requestPaint,
now,
NormalPriority as NormalSchedulerPriority,
IdlePriority as IdleSchedulerPriority,
} from './Scheduler';
import {
logCommitStarted,
logCommitStopped,
logLayoutEffectsStarted,
logLayoutEffectsStopped,
logPassiveEffectsStarted,
logPassiveEffectsStopped,
logRenderStarted,
logRenderStopped,
} from './DebugTracing';
import {
logBlockingStart,
logTransitionStart,
logRenderPhase,
logSuspenseThrottlePhase,
logSuspendedCommitPhase,
logCommitPhase,
logPaintYieldPhase,
logPassiveCommitPhase,
} from './ReactFiberPerformanceTrack';
import {
resetAfterCommit,
scheduleTimeout,
cancelTimeout,
noTimeout,
afterActiveInstanceBlur,
startSuspendingCommit,
waitForCommitToBeReady,
preloadInstance,
preloadResource,
supportsHydration,
setCurrentUpdatePriority,
getCurrentUpdatePriority,
resolveUpdatePriority,
} from './ReactFiberConfig';
import {createWorkInProgress, resetWorkInProgress} from './ReactFiber';
import {isRootDehydrated} from './ReactFiberShellHydration';
import {getIsHydrating} from './ReactFiberHydrationContext';
import {
NoMode,
ProfileMode,
ConcurrentMode,
StrictLegacyMode,
StrictEffectsMode,
NoStrictPassiveEffectsMode,
} from './ReactTypeOfMode';
import {
HostRoot,
ClassComponent,
SuspenseComponent,
SuspenseListComponent,
OffscreenComponent,
FunctionComponent,
ForwardRef,
MemoComponent,
SimpleMemoComponent,
HostComponent,
HostHoistable,
HostSingleton,
} from './ReactWorkTags';
import {ConcurrentRoot, LegacyRoot} from './ReactRootTags';
import type {Flags} from './ReactFiberFlags';
import {
NoFlags,
Incomplete,
StoreConsistency,
HostEffectMask,
ForceClientRender,
BeforeMutationMask,
MutationMask,
LayoutMask,
PassiveMask,
PlacementDEV,
Visibility,
MountPassiveDev,
MountLayoutDev,
DidDefer,
ShouldSuspendCommit,
MaySuspendCommit,
ScheduleRetry,
} from './ReactFiberFlags';
import {
NoLanes,
NoLane,
SyncLane,
claimNextRetryLane,
includesSyncLane,
isSubsetOfLanes,
mergeLanes,
removeLanes,
pickArbitraryLane,
includesNonIdleWork,
includesOnlyRetries,
includesOnlyTransitions,
includesBlockingLane,
includesTransitionLane,
includesExpiredLane,
getNextLanes,
getEntangledLanes,
getLanesToRetrySynchronouslyOnError,
upgradePendingLanesToSync,
markRootSuspended as _markRootSuspended,
markRootUpdated as _markRootUpdated,
markRootPinged as _markRootPinged,
markRootFinished,
addFiberToLanesMap,
movePendingFibersToMemoized,
addTransitionToLanesMap,
getTransitionsForLanes,
includesSomeLane,
OffscreenLane,
SyncUpdateLanes,
UpdateLanes,
claimNextTransitionLane,
checkIfRootIsPrerendering,
} from './ReactFiberLane';
import {
DiscreteEventPriority,
DefaultEventPriority,
lowerEventPriority,
lanesToEventPriority,
eventPriorityToLane,
} from './ReactEventPriorities';
import {requestCurrentTransition} from './ReactFiberTransition';
import {
SelectiveHydrationException,
beginWork,
replayFunctionComponent,
} from './ReactFiberBeginWork';
import {completeWork} from './ReactFiberCompleteWork';
import {unwindWork, unwindInterruptedWork} from './ReactFiberUnwindWork';
import {
throwException,
createRootErrorUpdate,
createClassErrorUpdate,
initializeClassErrorUpdate,
} from './ReactFiberThrow';
import {
commitBeforeMutationEffects,
commitLayoutEffects,
commitMutationEffects,
commitPassiveMountEffects,
commitPassiveUnmountEffects,
disappearLayoutEffects,
reconnectPassiveEffects,
reappearLayoutEffects,
disconnectPassiveEffect,
invokeLayoutEffectMountInDEV,
invokePassiveEffectMountInDEV,
invokeLayoutEffectUnmountInDEV,
invokePassiveEffectUnmountInDEV,
accumulateSuspenseyCommit,
} from './ReactFiberCommitWork';
import {enqueueUpdate} from './ReactFiberClassUpdateQueue';
import {resetContextDependencies} from './ReactFiberNewContext';
import {
resetHooksAfterThrow,
resetHooksOnUnwind,
ContextOnlyDispatcher,
} from './ReactFiberHooks';
import {DefaultAsyncDispatcher} from './ReactFiberAsyncDispatcher';
import {
createCapturedValueAtFiber,
type CapturedValue,
} from './ReactCapturedValue';
import {
enqueueConcurrentRenderForLane,
finishQueueingConcurrentUpdates,
getConcurrentlyUpdatedLanes,
} from './ReactFiberConcurrentUpdates';
import {
blockingUpdateTime,
blockingEventTime,
blockingEventType,
transitionStartTime,
transitionUpdateTime,
transitionEventTime,
transitionEventType,
clearBlockingTimers,
clearTransitionTimers,
clampBlockingTimers,
clampTransitionTimers,
markNestedUpdateScheduled,
renderStartTime,
commitStartTime,
commitEndTime,
recordRenderTime,
recordCommitTime,
recordCommitEndTime,
startProfilerTimer,
stopProfilerTimerIfRunningAndRecordDuration,
stopProfilerTimerIfRunningAndRecordIncompleteDuration,
} from './ReactProfilerTimer';
import {setCurrentTrackFromLanes} from './ReactFiberPerformanceTrack';
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
import {
isRendering as ReactCurrentDebugFiberIsRenderingInDEV,
resetCurrentFiber,
runWithFiberInDEV,
} from './ReactCurrentFiber';
import {
isDevToolsPresent,
markCommitStarted,
markCommitStopped,
markComponentRenderStopped,
markComponentSuspended,
markComponentErrored,
markLayoutEffectsStarted,
markLayoutEffectsStopped,
markPassiveEffectsStarted,
markPassiveEffectsStopped,
markRenderStarted,
markRenderYielded,
markRenderStopped,
onCommitRoot as onCommitRootDevTools,
onPostCommitRoot as onPostCommitRootDevTools,
setIsStrictModeForDevtools,
} from './ReactFiberDevToolsHook';
import {onCommitRoot as onCommitRootTestSelector} from './ReactTestSelectors';
import {releaseCache} from './ReactFiberCacheComponent';
import {
isLegacyActEnvironment,
isConcurrentActEnvironment,
} from './ReactFiberAct';
import {processTransitionCallbacks} from './ReactFiberTracingMarkerComponent';
import {
SuspenseException,
SuspenseyCommitException,
getSuspendedThenable,
isThenableResolved,
} from './ReactFiberThenable';
import {schedulePostPaintCallback} from './ReactPostPaintCallback';
import {
getSuspenseHandler,
getShellBoundary,
} from './ReactFiberSuspenseContext';
import {resolveDefaultPropsOnNonClassComponent} from './ReactFiberLazyComponent';
import {resetChildReconcilerOnUnwind} from './ReactChildFiber';
import {
ensureRootIsScheduled,
flushSyncWorkOnAllRoots,
flushSyncWorkOnLegacyRootsOnly,
requestTransitionLane,
} from './ReactFiberRootScheduler';
import {getMaskedContext, getUnmaskedContext} from './ReactFiberContext';
import {peekEntangledActionLane} from './ReactFiberAsyncAction';
import {logUncaughtError} from './ReactFiberErrorLogger';
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
type ExecutionContext = number;
export const NoContext = 0b000;
const BatchedContext = 0b001;
export const RenderContext = 0b010;
export const CommitContext = 0b100;
type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6;
const RootInProgress = 0;
const RootFatalErrored = 1;
const RootErrored = 2;
const RootSuspended = 3;
const RootSuspendedWithDelay = 4;
const RootCompleted = 5;
const RootDidNotComplete = 6;
let executionContext: ExecutionContext = NoContext;
let workInProgressRoot: FiberRoot | null = null;
let workInProgress: Fiber | null = null;
let workInProgressRootRenderLanes: Lanes = NoLanes;
opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
const NotSuspended: SuspendedReason = 0;
const SuspendedOnError: SuspendedReason = 1;
const SuspendedOnData: SuspendedReason = 2;
const SuspendedOnImmediate: SuspendedReason = 3;
const SuspendedOnInstance: SuspendedReason = 4;
const SuspendedOnInstanceAndReadyToContinue: SuspendedReason = 5;
const SuspendedOnDeprecatedThrowPromise: SuspendedReason = 6;
const SuspendedAndReadyToContinue: SuspendedReason = 7;
const SuspendedOnHydration: SuspendedReason = 8;
let workInProgressSuspendedReason: SuspendedReason = NotSuspended;
let workInProgressThrownValue: mixed = null;
let workInProgressRootDidSkipSuspendedSiblings: boolean = false;
let workInProgressRootIsPrerendering: boolean = false;
let workInProgressRootDidAttachPingListener: boolean = false;
export let entangledRenderLanes: Lanes = NoLanes;
let workInProgressRootExitStatus: RootExitStatus = RootInProgress;
let workInProgressRootSkippedLanes: Lanes = NoLanes;
let workInProgressRootInterleavedUpdatedLanes: Lanes = NoLanes;
let workInProgressRootRenderPhaseUpdatedLanes: Lanes = NoLanes;
let workInProgressRootPingedLanes: Lanes = NoLanes;
let workInProgressDeferredLane: Lane = NoLane;
let workInProgressSuspendedRetryLanes: Lanes = NoLanes;
let workInProgressRootConcurrentErrors: Array<CapturedValue<mixed>> | null =
null;
let workInProgressRootRecoverableErrors: Array<CapturedValue<mixed>> | null =
null;
let workInProgressRootDidIncludeRecursiveRenderUpdate: boolean = false;
let didIncludeCommitPhaseUpdate: boolean = false;
let globalMostRecentFallbackTime: number = 0;
const FALLBACK_THROTTLE_MS: number = 300;
let workInProgressRootRenderTargetTime: number = Infinity;
const RENDER_TIMEOUT_MS = 500;
let workInProgressTransitions: Array<Transition> | null = null;
export function getWorkInProgressTransitions(): null | Array<Transition> {
return workInProgressTransitions;
}
let currentPendingTransitionCallbacks: PendingTransitionCallbacks | null = null;
let currentEndTime: number | null = null;
export function addTransitionStartCallbackToPendingTransition(
transition: Transition,
) {
if (enableTransitionTracing) {
if (currentPendingTransitionCallbacks === null) {
currentPendingTransitionCallbacks = {
transitionStart: [],
transitionProgress: null,
transitionComplete: null,
markerProgress: null,
markerIncomplete: null,
markerComplete: null,
};
}
if (currentPendingTransitionCallbacks.transitionStart === null) {
currentPendingTransitionCallbacks.transitionStart =
([]: Array<Transition>);
}
currentPendingTransitionCallbacks.transitionStart.push(transition);
}
}
export function addMarkerProgressCallbackToPendingTransition(
markerName: string,
transitions: Set<Transition>,
pendingBoundaries: PendingBoundaries,
) {
if (enableTransitionTracing) {
if (currentPendingTransitionCallbacks === null) {
currentPendingTransitionCallbacks = ({
transitionStart: null,
transitionProgress: null,
transitionComplete: null,
markerProgress: new Map(),
markerIncomplete: null,
markerComplete: null,
}: PendingTransitionCallbacks);
}
if (currentPendingTransitionCallbacks.markerProgress === null) {
currentPendingTransitionCallbacks.markerProgress = new Map();
}
currentPendingTransitionCallbacks.markerProgress.set(markerName, {
pendingBoundaries,
transitions,
});
}
}
export function addMarkerIncompleteCallbackToPendingTransition(
markerName: string,
transitions: Set<Transition>,
aborts: Array<TransitionAbort>,
) {
if (enableTransitionTracing) {
if (currentPendingTransitionCallbacks === null) {
currentPendingTransitionCallbacks = {
transitionStart: null,
transitionProgress: null,
transitionComplete: null,
markerProgress: null,
markerIncomplete: new Map(),
markerComplete: null,
};
}
if (currentPendingTransitionCallbacks.markerIncomplete === null) {
currentPendingTransitionCallbacks.markerIncomplete = new Map();
}
currentPendingTransitionCallbacks.markerIncomplete.set(markerName, {
transitions,
aborts,
});
}
}
export function addMarkerCompleteCallbackToPendingTransition(
markerName: string,
transitions: Set<Transition>,
) {
if (enableTransitionTracing) {
if (currentPendingTransitionCallbacks === null) {
currentPendingTransitionCallbacks = {
transitionStart: null,
transitionProgress: null,
transitionComplete: null,
markerProgress: null,
markerIncomplete: null,
markerComplete: new Map(),
};
}
if (currentPendingTransitionCallbacks.markerComplete === null) {
currentPendingTransitionCallbacks.markerComplete = new Map();
}
currentPendingTransitionCallbacks.markerComplete.set(
markerName,
transitions,
);
}
}
export function addTransitionProgressCallbackToPendingTransition(
transition: Transition,
boundaries: PendingBoundaries,
) {
if (enableTransitionTracing) {
if (currentPendingTransitionCallbacks === null) {
currentPendingTransitionCallbacks = {
transitionStart: null,
transitionProgress: new Map(),
transitionComplete: null,
markerProgress: null,
markerIncomplete: null,
markerComplete: null,
};
}
if (currentPendingTransitionCallbacks.transitionProgress === null) {
currentPendingTransitionCallbacks.transitionProgress = new Map();
}
currentPendingTransitionCallbacks.transitionProgress.set(
transition,
boundaries,
);
}
}
export function addTransitionCompleteCallbackToPendingTransition(
transition: Transition,
) {
if (enableTransitionTracing) {
if (currentPendingTransitionCallbacks === null) {
currentPendingTransitionCallbacks = {
transitionStart: null,
transitionProgress: null,
transitionComplete: [],
markerProgress: null,
markerIncomplete: null,
markerComplete: null,
};
}
if (currentPendingTransitionCallbacks.transitionComplete === null) {
currentPendingTransitionCallbacks.transitionComplete =
([]: Array<Transition>);
}
currentPendingTransitionCallbacks.transitionComplete.push(transition);
}
}
function resetRenderTimer() {
workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;
}
export function getRenderTargetTime(): number {
return workInProgressRootRenderTargetTime;
}
let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;
let rootDoesHavePassiveEffects: boolean = false;
let rootWithPendingPassiveEffects: FiberRoot | null = null;
let pendingPassiveEffectsLanes: Lanes = NoLanes;
let pendingPassiveEffectsRemainingLanes: Lanes = NoLanes;
let pendingPassiveEffectsRenderEndTime: number = -0;
let pendingPassiveTransitions: Array<Transition> | null = null;
const NESTED_UPDATE_LIMIT = 50;
let nestedUpdateCount: number = 0;
let rootWithNestedUpdates: FiberRoot | null = null;
let isFlushingPassiveEffects = false;
let didScheduleUpdateDuringPassiveEffects = false;
const NESTED_PASSIVE_UPDATE_LIMIT = 50;
let nestedPassiveUpdateCount: number = 0;
let rootWithPassiveNestedUpdates: FiberRoot | null = null;
let isRunningInsertionEffect = false;
export function getWorkInProgressRoot(): FiberRoot | null {
return workInProgressRoot;
}
export function getWorkInProgressRootRenderLanes(): Lanes {
return workInProgressRootRenderLanes;
}
export function isWorkLoopSuspendedOnData(): boolean {
return workInProgressSuspendedReason === SuspendedOnData;
}
export function getCurrentTime(): number {
return now();
}
export function requestUpdateLane(fiber: Fiber): Lane {
const mode = fiber.mode;
if (!disableLegacyMode && (mode & ConcurrentMode) === NoMode) {
return (SyncLane: Lane);
} else if (
(executionContext & RenderContext) !== NoContext &&
workInProgressRootRenderLanes !== NoLanes
) {
return pickArbitraryLane(workInProgressRootRenderLanes);
}
const transition = requestCurrentTransition();
if (transition !== null) {
if (__DEV__) {
if (!transition._updatedFibers) {
transition._updatedFibers = new Set();
}
transition._updatedFibers.add(fiber);
}
const actionScopeLane = peekEntangledActionLane();
return actionScopeLane !== NoLane
?
actionScopeLane
:
requestTransitionLane(transition);
}
return eventPriorityToLane(resolveUpdatePriority());
}
function requestRetryLane(fiber: Fiber) {
const mode = fiber.mode;
if (!disableLegacyMode && (mode & ConcurrentMode) === NoMode) {
return (SyncLane: Lane);
}
return claimNextRetryLane();
}
export function requestDeferredLane(): Lane {
if (workInProgressDeferredLane === NoLane) {
const isPrerendering =
includesSomeLane(workInProgressRootRenderLanes, OffscreenLane) &&
!getIsHydrating();
if (isPrerendering) {
workInProgressDeferredLane = OffscreenLane;
} else {
workInProgressDeferredLane = claimNextTransitionLane();
}
}
const suspenseHandler = getSuspenseHandler();
if (suspenseHandler !== null) {
suspenseHandler.flags |= DidDefer;
}
return workInProgressDeferredLane;
}
export function peekDeferredLane(): Lane {
return workInProgressDeferredLane;
}
export function scheduleUpdateOnFiber(
root: FiberRoot,
fiber: Fiber,
lane: Lane,
) {
if (__DEV__) {
if (isRunningInsertionEffect) {
console.error('useInsertionEffect must not schedule updates.');
}
}
if (__DEV__) {
if (isFlushingPassiveEffects) {
didScheduleUpdateDuringPassiveEffects = true;
}
}
if (
(root === workInProgressRoot &&
workInProgressSuspendedReason === SuspendedOnData) ||
root.cancelPendingCommit !== null
) {
prepareFreshStack(root, NoLanes);
markRootSuspended(
root,
workInProgressRootRenderLanes,
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings,
);
}
markRootUpdated(root, lane);
if (
(executionContext & RenderContext) !== NoLanes &&
root === workInProgressRoot
) {
warnAboutRenderPhaseUpdatesInDEV(fiber);
workInProgressRootRenderPhaseUpdatedLanes = mergeLanes(
workInProgressRootRenderPhaseUpdatedLanes,
lane,
);
} else {
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
addFiberToLanesMap(root, fiber, lane);
}
}
warnIfUpdatesNotWrappedWithActDEV(fiber);
if (enableTransitionTracing) {
const transition = ReactSharedInternals.T;
if (transition !== null && transition.name != null) {
if (transition.startTime === -1) {
transition.startTime = now();
}
addTransitionToLanesMap(root, transition, lane);
}
}
if (root === workInProgressRoot) {
if ((executionContext & RenderContext) === NoContext) {
workInProgressRootInterleavedUpdatedLanes = mergeLanes(
workInProgressRootInterleavedUpdatedLanes,
lane,
);
}
if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
markRootSuspended(
root,
workInProgressRootRenderLanes,
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings,
);
}
}
ensureRootIsScheduled(root);
if (
lane === SyncLane &&
executionContext === NoContext &&
!disableLegacyMode &&
(fiber.mode & ConcurrentMode) === NoMode
) {
if (__DEV__ && ReactSharedInternals.isBatchingLegacy) {
} else {
resetRenderTimer();
flushSyncWorkOnLegacyRootsOnly();
}
}
}
}
export function scheduleInitialHydrationOnRoot(root: FiberRoot, lane: Lane) {
const current = root.current;
current.lanes = lane;
markRootUpdated(root, lane);
ensureRootIsScheduled(root);
}
export function isUnsafeClassRenderPhaseUpdate(fiber: Fiber): boolean {
return (executionContext & RenderContext) !== NoContext;
}
export function performWorkOnRoot(
root: FiberRoot,
lanes: Lanes,
forceSync: boolean,
): void {
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.');
}
const shouldTimeSlice =
!forceSync &&
!includesBlockingLane(lanes) &&
!includesExpiredLane(root, lanes);
let exitStatus = shouldTimeSlice
? renderRootConcurrent(root, lanes)
: renderRootSync(root, lanes);
if (exitStatus !== RootInProgress) {
let renderWasConcurrent = shouldTimeSlice;
do {
if (exitStatus === RootDidNotComplete) {
markRootSuspended(
root,
lanes,
NoLane,
workInProgressRootDidSkipSuspendedSiblings,
);
} else {
const finishedWork: Fiber = (root.current.alternate: any);
if (
renderWasConcurrent &&
!isRenderConsistentWithExternalStores(finishedWork)
) {
exitStatus = renderRootSync(root, lanes);
renderWasConcurrent = false;
continue;
}
if (
(disableLegacyMode || root.tag !== LegacyRoot) &&
exitStatus === RootErrored
) {
const lanesThatJustErrored = lanes;
const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
root,
lanesThatJustErrored,
);
if (errorRetryLanes !== NoLanes) {
lanes = errorRetryLanes;
exitStatus = recoverFromConcurrentError(
root,
lanesThatJustErrored,
errorRetryLanes,
);
renderWasConcurrent = false;
if (exitStatus !== RootErrored) {
continue;
} else {
}
}
}
if (exitStatus === RootFatalErrored) {
prepareFreshStack(root, NoLanes);
markRootSuspended(
root,
lanes,
NoLane,
workInProgressRootDidSkipSuspendedSiblings,
);
break;
}
finishConcurrentRender(root, exitStatus, finishedWork, lanes);
}
break;
} while (true);
}
ensureRootIsScheduled(root);
}
function recoverFromConcurrentError(
root: FiberRoot,
originallyAttemptedLanes: Lanes,
errorRetryLanes: Lanes,
) {
const errorsFromFirstAttempt = workInProgressRootConcurrentErrors;
const wasRootDehydrated = supportsHydration && isRootDehydrated(root);
if (wasRootDehydrated) {
const rootWorkInProgress = prepareFreshStack(root, errorRetryLanes);
rootWorkInProgress.flags |= ForceClientRender;
}
const exitStatus = renderRootSync(root, errorRetryLanes);
if (exitStatus !== RootErrored) {
if (workInProgressRootDidAttachPingListener && !wasRootDehydrated) {
root.errorRecoveryDisabledLanes = mergeLanes(
root.errorRecoveryDisabledLanes,
originallyAttemptedLanes,
);
workInProgressRootInterleavedUpdatedLanes |= originallyAttemptedLanes;
return RootSuspendedWithDelay;
}
const errorsFromSecondAttempt = workInProgressRootRecoverableErrors;
workInProgressRootRecoverableErrors = errorsFromFirstAttempt;
if (errorsFromSecondAttempt !== null) {
queueRecoverableErrors(errorsFromSecondAttempt);
}
} else {
}
return exitStatus;
}
export function queueRecoverableErrors(errors: Array<CapturedValue<mixed>>) {
if (workInProgressRootRecoverableErrors === null) {
workInProgressRootRecoverableErrors = errors;
} else {
workInProgressRootRecoverableErrors.push.apply(
workInProgressRootRecoverableErrors,
errors,
);
}
}
function finishConcurrentRender(
root: FiberRoot,
exitStatus: RootExitStatus,
finishedWork: Fiber,
lanes: Lanes,
) {
let renderEndTime = 0;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
renderEndTime = now();
}
switch (exitStatus) {
case RootInProgress:
case RootFatalErrored: {
throw new Error('Root did not complete. This is a bug in React.');
}
case RootSuspendedWithDelay: {
if (includesOnlyTransitions(lanes)) {
markRootSuspended(
root,
lanes,
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings,
);
return;
}
break;
}
case RootErrored: {
workInProgressRootRecoverableErrors = null;
break;
}
case RootSuspended:
case RootCompleted: {
break;
}
default: {
throw new Error('Unknown root exit status.');
}
}
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
if (shouldForceFlushFallbacksInDEV()) {
commitRoot(
root,
workInProgressRootRecoverableErrors,
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
workInProgressDeferredLane,
workInProgressRootInterleavedUpdatedLanes,
workInProgressSuspendedRetryLanes,
IMMEDIATE_COMMIT,
renderStartTime,
renderEndTime,
);
} else {
if (
includesOnlyRetries(lanes) &&
(alwaysThrottleRetries || exitStatus === RootSuspended)
) {
const msUntilTimeout =
globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();
if (msUntilTimeout > 10) {
markRootSuspended(
root,
lanes,
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings,
);
const nextLanes = getNextLanes(root, NoLanes);
if (nextLanes !== NoLanes) {
return;
}
root.timeoutHandle = scheduleTimeout(
commitRootWhenReady.bind(
null,
root,
finishedWork,
workInProgressRootRecoverableErrors,
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
lanes,
workInProgressDeferredLane,
workInProgressRootInterleavedUpdatedLanes,
workInProgressSuspendedRetryLanes,
workInProgressRootDidSkipSuspendedSiblings,
THROTTLED_COMMIT,
renderStartTime,
renderEndTime,
),
msUntilTimeout,
);
return;
}
}
commitRootWhenReady(
root,
finishedWork,
workInProgressRootRecoverableErrors,
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
lanes,
workInProgressDeferredLane,
workInProgressRootInterleavedUpdatedLanes,
workInProgressSuspendedRetryLanes,
workInProgressRootDidSkipSuspendedSiblings,
IMMEDIATE_COMMIT,
renderStartTime,
renderEndTime,
);
}
}
function commitRootWhenReady(
root: FiberRoot,
finishedWork: Fiber,
recoverableErrors: Array<CapturedValue<mixed>> | null,
transitions: Array<Transition> | null,
didIncludeRenderPhaseUpdate: boolean,
lanes: Lanes,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
didSkipSuspendedSiblings: boolean,
suspendedCommitReason: SuspendedCommitReason,
completedRenderStartTime: number,
completedRenderEndTime: number,
) {
const BothVisibilityAndMaySuspendCommit = Visibility | MaySuspendCommit;
const subtreeFlags = finishedWork.subtreeFlags;
if (
subtreeFlags & ShouldSuspendCommit ||
(subtreeFlags & BothVisibilityAndMaySuspendCommit) ===
BothVisibilityAndMaySuspendCommit
) {
startSuspendingCommit();
accumulateSuspenseyCommit(finishedWork);
const schedulePendingCommit = waitForCommitToBeReady();
if (schedulePendingCommit !== null) {
root.cancelPendingCommit = schedulePendingCommit(
commitRoot.bind(
null,
root,
recoverableErrors,
transitions,
didIncludeRenderPhaseUpdate,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
SUSPENDED_COMMIT,
completedRenderStartTime,
completedRenderEndTime,
),
);
markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings);
return;
}
}
commitRoot(
root,
recoverableErrors,
transitions,
didIncludeRenderPhaseUpdate,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
suspendedCommitReason,
completedRenderStartTime,
completedRenderEndTime,
);
}
function isRenderConsistentWithExternalStores(finishedWork: Fiber): boolean {
let node: Fiber = finishedWork;
while (true) {
const tag = node.tag;
if (
(tag === FunctionComponent ||
tag === ForwardRef ||
tag === SimpleMemoComponent) &&
node.flags & StoreConsistency
) {
const updateQueue: FunctionComponentUpdateQueue | null =
(node.updateQueue: any);
if (updateQueue !== null) {
const checks = updateQueue.stores;
if (checks !== null) {
for (let i = 0; i < checks.length; i++) {
const check = checks[i];
const getSnapshot = check.getSnapshot;
const renderedValue = check.value;
try {
if (!is(getSnapshot(), renderedValue)) {
return false;
}
} catch (error) {
return false;
}
}
}
}
}
const child = node.child;
if (node.subtreeFlags & StoreConsistency && child !== null) {
child.return = node;
node = child;
continue;
}
if (node === finishedWork) {
return true;
}
while (node.sibling === null) {
if (node.return === null || node.return === finishedWork) {
return true;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
return true;
}
function markRootUpdated(root: FiberRoot, updatedLanes: Lanes) {
_markRootUpdated(root, updatedLanes);
if (enableInfiniteRenderLoopDetection) {
if (executionContext & RenderContext) {
workInProgressRootDidIncludeRecursiveRenderUpdate = true;
} else if (executionContext & CommitContext) {
didIncludeCommitPhaseUpdate = true;
}
throwIfInfiniteUpdateLoopDetected();
}
}
function markRootPinged(root: FiberRoot, pingedLanes: Lanes) {
_markRootPinged(root, pingedLanes);
if (enableInfiniteRenderLoopDetection) {
if (executionContext & RenderContext) {
workInProgressRootDidIncludeRecursiveRenderUpdate = true;
} else if (executionContext & CommitContext) {
didIncludeCommitPhaseUpdate = true;
}
throwIfInfiniteUpdateLoopDetected();
}
}
function markRootSuspended(
root: FiberRoot,
suspendedLanes: Lanes,
spawnedLane: Lane,
didSkipSuspendedSiblings: boolean,
) {
suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);
suspendedLanes = removeLanes(
suspendedLanes,
workInProgressRootInterleavedUpdatedLanes,
);
_markRootSuspended(
root,
suspendedLanes,
spawnedLane,
didSkipSuspendedSiblings,
);
}
export function flushRoot(root: FiberRoot, lanes: Lanes) {
if (lanes !== NoLanes) {
upgradePendingLanesToSync(root, lanes);
ensureRootIsScheduled(root);
if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
resetRenderTimer();
flushSyncWorkOnAllRoots();
}
}
}
export function getExecutionContext(): ExecutionContext {
return executionContext;
}
export function deferredUpdates<A>(fn: () => A): A {
const prevTransition = ReactSharedInternals.T;
const previousPriority = getCurrentUpdatePriority();
try {
setCurrentUpdatePriority(DefaultEventPriority);
ReactSharedInternals.T = null;
return fn();
} finally {
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
}
export function batchedUpdates<A, R>(fn: A => R, a: A): R {
if (disableLegacyMode) {
return fn(a);
} else {
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
try {
return fn(a);
} finally {
executionContext = prevExecutionContext;
if (
executionContext === NoContext &&
!(__DEV__ && ReactSharedInternals.isBatchingLegacy)
) {
resetRenderTimer();
flushSyncWorkOnLegacyRootsOnly();
}
}
}
}
export function discreteUpdates<A, B, C, D, R>(
fn: (A, B, C, D) => R,
a: A,
b: B,
c: C,
d: D,
): R {
const prevTransition = ReactSharedInternals.T;
const previousPriority = getCurrentUpdatePriority();
try {
setCurrentUpdatePriority(DiscreteEventPriority);
ReactSharedInternals.T = null;
return fn(a, b, c, d);
} finally {
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
if (executionContext === NoContext) {
resetRenderTimer();
}
}
}
declare function flushSyncFromReconciler<R>(fn: () => R): R;
declare function flushSyncFromReconciler(void): void;
export function flushSyncFromReconciler<R>(fn: (() => R) | void): R | void {
if (
rootWithPendingPassiveEffects !== null &&
!disableLegacyMode &&
rootWithPendingPassiveEffects.tag === LegacyRoot &&
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
flushPassiveEffects();
}
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
const prevTransition = ReactSharedInternals.T;
const previousPriority = getCurrentUpdatePriority();
try {
setCurrentUpdatePriority(DiscreteEventPriority);
ReactSharedInternals.T = null;
if (fn) {
return fn();
} else {
return undefined;
}
} finally {
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
executionContext = prevExecutionContext;
if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
flushSyncWorkOnAllRoots();
}
}
}
export function flushSyncWork(): boolean {
if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
flushSyncWorkOnAllRoots();
return false;
}
return true;
}
export function isAlreadyRendering(): boolean {
return (
__DEV__ &&
(executionContext & (RenderContext | CommitContext)) !== NoContext
);
}
export function isInvalidExecutionContextForEventFunction(): boolean {
return (executionContext & RenderContext) !== NoContext;
}
export function setEntangledRenderLanes(newEntangledRenderLanes: Lanes) {
entangledRenderLanes = newEntangledRenderLanes;
}
export function getEntangledRenderLanes(): Lanes {
return entangledRenderLanes;
}
function resetWorkInProgressStack() {
if (workInProgress === null) return;
let interruptedWork;
if (workInProgressSuspendedReason === NotSuspended) {
interruptedWork = workInProgress.return;
} else {
resetSuspendedWorkLoopOnUnwind(workInProgress);
interruptedWork = workInProgress;
}
while (interruptedWork !== null) {
const current = interruptedWork.alternate;
unwindInterruptedWork(
current,
interruptedWork,
workInProgressRootRenderLanes,
);
interruptedWork = interruptedWork.return;
}
workInProgress = null;
}
function finalizeRender(lanes: Lanes, finalizationTime: number): void {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (includesSyncLane(lanes) || includesBlockingLane(lanes)) {
clampBlockingTimers(finalizationTime);
}
if (includesTransitionLane(lanes)) {
clampTransitionTimers(finalizationTime);
}
}
}
function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
recordRenderTime();
finalizeRender(workInProgressRootRenderLanes, renderStartTime);
if (includesSyncLane(lanes) || includesBlockingLane(lanes)) {
logBlockingStart(
blockingUpdateTime,
blockingEventTime,
blockingEventType,
renderStartTime,
);
clearBlockingTimers();
}
if (includesTransitionLane(lanes)) {
logTransitionStart(
transitionStartTime,
transitionUpdateTime,
transitionEventTime,
transitionEventType,
renderStartTime,
);
clearTransitionTimers();
}
}
root.finishedWork = null;
root.finishedLanes = NoLanes;
const timeoutHandle = root.timeoutHandle;
if (timeoutHandle !== noTimeout) {
root.timeoutHandle = noTimeout;
cancelTimeout(timeoutHandle);
}
const cancelPendingCommit = root.cancelPendingCommit;
if (cancelPendingCommit !== null) {
root.cancelPendingCommit = null;
cancelPendingCommit();
}
resetWorkInProgressStack();
workInProgressRoot = root;
const rootWorkInProgress = createWorkInProgress(root.current, null);
workInProgress = rootWorkInProgress;
workInProgressRootRenderLanes = lanes;
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
workInProgressRootDidSkipSuspendedSiblings = false;
workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes);
workInProgressRootDidAttachPingListener = false;
workInProgressRootExitStatus = RootInProgress;
workInProgressRootSkippedLanes = NoLanes;
workInProgressRootInterleavedUpdatedLanes = NoLanes;
workInProgressRootRenderPhaseUpdatedLanes = NoLanes;
workInProgressRootPingedLanes = NoLanes;
workInProgressDeferredLane = NoLane;
workInProgressSuspendedRetryLanes = NoLanes;
workInProgressRootConcurrentErrors = null;
workInProgressRootRecoverableErrors = null;
workInProgressRootDidIncludeRecursiveRenderUpdate = false;
entangledRenderLanes = getEntangledLanes(root, lanes);
finishQueueingConcurrentUpdates();
if (__DEV__) {
ReactStrictModeWarnings.discardPendingWarnings();
}
return rootWorkInProgress;
}
function resetSuspendedWorkLoopOnUnwind(fiber: Fiber) {
resetContextDependencies();
resetHooksOnUnwind(fiber);
resetChildReconcilerOnUnwind();
}
function handleThrow(root: FiberRoot, thrownValue: any): void {
resetHooksAfterThrow();
if (__DEV__ || !disableStringRefs) {
resetCurrentFiber();
}
if (thrownValue === SuspenseException) {
thrownValue = getSuspendedThenable();
workInProgressSuspendedReason =
!enableSiblingPrerendering &&
shouldRemainOnPreviousScreen() &&
!includesNonIdleWork(workInProgressRootSkippedLanes) &&
!includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)
?
SuspendedOnData
:
SuspendedOnImmediate;
} else if (thrownValue === SuspenseyCommitException) {
thrownValue = getSuspendedThenable();
workInProgressSuspendedReason = SuspendedOnInstance;
} else if (thrownValue === SelectiveHydrationException) {
workInProgressSuspendedReason = SuspendedOnHydration;
} else {
const isWakeable =
thrownValue !== null &&
typeof thrownValue === 'object' &&
typeof thrownValue.then === 'function';
workInProgressSuspendedReason = isWakeable
?
SuspendedOnDeprecatedThrowPromise
:
SuspendedOnError;
}
workInProgressThrownValue = thrownValue;
const erroredWork = workInProgress;
if (erroredWork === null) {
workInProgressRootExitStatus = RootFatalErrored;
logUncaughtError(
root,
createCapturedValueAtFiber(thrownValue, root.current),
);
return;
}
if (enableProfilerTimer && erroredWork.mode & ProfileMode) {
stopProfilerTimerIfRunningAndRecordDuration(erroredWork);
}
if (enableSchedulingProfiler) {
markComponentRenderStopped();
switch (workInProgressSuspendedReason) {
case SuspendedOnError: {
markComponentErrored(
erroredWork,
thrownValue,
workInProgressRootRenderLanes,
);
break;
}
case SuspendedOnData:
case SuspendedOnImmediate:
case SuspendedOnDeprecatedThrowPromise:
case SuspendedAndReadyToContinue: {
const wakeable: Wakeable = (thrownValue: any);
markComponentSuspended(
erroredWork,
wakeable,
workInProgressRootRenderLanes,
);
break;
}
case SuspendedOnInstance: {
break;
}
case SuspendedOnHydration: {
break;
}
}
}
}
export function shouldRemainOnPreviousScreen(): boolean {
const handler = getSuspenseHandler();
if (handler === null) {
return true;
}
if (includesOnlyTransitions(workInProgressRootRenderLanes)) {
if (getShellBoundary() === null) {
return true;
} else {
return false;
}
}
if (
includesOnlyRetries(workInProgressRootRenderLanes) ||
includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
) {
return handler === getShellBoundary();
}
return false;
}
function pushDispatcher(container: any) {
const prevDispatcher = ReactSharedInternals.H;
ReactSharedInternals.H = ContextOnlyDispatcher;
if (prevDispatcher === null) {
return ContextOnlyDispatcher;
} else {
return prevDispatcher;
}
}
function popDispatcher(prevDispatcher: any) {
ReactSharedInternals.H = prevDispatcher;
}
function pushAsyncDispatcher() {
if (enableCache || __DEV__ || !disableStringRefs) {
const prevAsyncDispatcher = ReactSharedInternals.A;
ReactSharedInternals.A = DefaultAsyncDispatcher;
return prevAsyncDispatcher;
} else {
return null;
}
}
function popAsyncDispatcher(prevAsyncDispatcher: any) {
if (enableCache || __DEV__ || !disableStringRefs) {
ReactSharedInternals.A = prevAsyncDispatcher;
}
}
export function markCommitTimeOfFallback() {
globalMostRecentFallbackTime = now();
}
export function markSkippedUpdateLanes(lane: Lane | Lanes): void {
workInProgressRootSkippedLanes = mergeLanes(
lane,
workInProgressRootSkippedLanes,
);
}
export function renderDidSuspend(): void {
if (workInProgressRootExitStatus === RootInProgress) {
workInProgressRootExitStatus = RootSuspended;
}
}
export function renderDidSuspendDelayIfPossible(): void {
workInProgressRootExitStatus = RootSuspendedWithDelay;
if (
!workInProgressRootDidSkipSuspendedSiblings &&
!includesBlockingLane(workInProgressRootRenderLanes)
) {
workInProgressRootIsPrerendering = true;
}
if (
(includesNonIdleWork(workInProgressRootSkippedLanes) ||
includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) &&
workInProgressRoot !== null
) {
markRootSuspended(
workInProgressRoot,
workInProgressRootRenderLanes,
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings,
);
}
}
export function renderDidError() {
if (workInProgressRootExitStatus !== RootSuspendedWithDelay) {
workInProgressRootExitStatus = RootErrored;
}
}
export function queueConcurrentError(error: CapturedValue<mixed>) {
if (workInProgressRootConcurrentErrors === null) {
workInProgressRootConcurrentErrors = [error];
} else {
workInProgressRootConcurrentErrors.push(error);
}
}
export function renderHasNotSuspendedYet(): boolean {
return workInProgressRootExitStatus === RootInProgress;
}
function renderRootSync(root: FiberRoot, lanes: Lanes) {
const prevExecutionContext = executionContext;
executionContext |= RenderContext;
const prevDispatcher = pushDispatcher(root.containerInfo);
const prevAsyncDispatcher = pushAsyncDispatcher();
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
const memoizedUpdaters = root.memoizedUpdaters;
if (memoizedUpdaters.size > 0) {
restorePendingUpdaters(root, workInProgressRootRenderLanes);
memoizedUpdaters.clear();
}
movePendingFibersToMemoized(root, lanes);
}
}
workInProgressTransitions = getTransitionsForLanes(root, lanes);
prepareFreshStack(root, lanes);
}
if (__DEV__) {
if (enableDebugTracing) {
logRenderStarted(lanes);
}
}
if (enableSchedulingProfiler) {
markRenderStarted(lanes);
}
let didSuspendInShell = false;
outer: do {
try {
if (
workInProgressSuspendedReason !== NotSuspended &&
workInProgress !== null
) {
const unitOfWork = workInProgress;
const thrownValue = workInProgressThrownValue;
switch (workInProgressSuspendedReason) {
case SuspendedOnHydration: {
resetWorkInProgressStack();
workInProgressRootExitStatus = RootDidNotComplete;
break outer;
}
case SuspendedOnImmediate:
case SuspendedOnData: {
if (!didSuspendInShell && getSuspenseHandler() === null) {
didSuspendInShell = true;
}
}
default: {
const reason = workInProgressSuspendedReason;
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason);
break;
}
}
}
workLoopSync();
break;
} catch (thrownValue) {
handleThrow(root, thrownValue);
}
} while (true);
if (didSuspendInShell) {
root.shellSuspendCounter++;
}
resetContextDependencies();
executionContext = prevExecutionContext;
popDispatcher(prevDispatcher);
popAsyncDispatcher(prevAsyncDispatcher);
if (workInProgress !== null) {
throw new Error(
'Cannot commit an incomplete root. This error is likely caused by a ' +
'bug in React. Please file an issue.',
);
}
if (__DEV__) {
if (enableDebugTracing) {
logRenderStopped();
}
}
if (enableSchedulingProfiler) {
markRenderStopped();
}
workInProgressRoot = null;
workInProgressRootRenderLanes = NoLanes;
finishQueueingConcurrentUpdates();
return workInProgressRootExitStatus;
}
function workLoopSync() {
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
const prevExecutionContext = executionContext;
executionContext |= RenderContext;
const prevDispatcher = pushDispatcher(root.containerInfo);
const prevAsyncDispatcher = pushAsyncDispatcher();
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
const memoizedUpdaters = root.memoizedUpdaters;
if (memoizedUpdaters.size > 0) {
restorePendingUpdaters(root, workInProgressRootRenderLanes);
memoizedUpdaters.clear();
}
movePendingFibersToMemoized(root, lanes);
}
}
workInProgressTransitions = getTransitionsForLanes(root, lanes);
resetRenderTimer();
prepareFreshStack(root, lanes);
} else {
if (workInProgressRootIsPrerendering) {
workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes);
}
}
if (__DEV__) {
if (enableDebugTracing) {
logRenderStarted(lanes);
}
}
if (enableSchedulingProfiler) {
markRenderStarted(lanes);
}
outer: do {
try {
if (
workInProgressSuspendedReason !== NotSuspended &&
workInProgress !== null
) {
const unitOfWork = workInProgress;
const thrownValue = workInProgressThrownValue;
resumeOrUnwind: switch (workInProgressSuspendedReason) {
case SuspendedOnError: {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedOnError,
);
break;
}
case SuspendedOnData: {
const thenable: Thenable<mixed> = (thrownValue: any);
if (isThenableResolved(thenable)) {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
replaySuspendedUnitOfWork(unitOfWork);
break;
}
const onResolution = () => {
if (
workInProgressSuspendedReason === SuspendedOnData &&
workInProgressRoot === root
) {
workInProgressSuspendedReason = SuspendedAndReadyToContinue;
}
ensureRootIsScheduled(root);
};
thenable.then(onResolution, onResolution);
break outer;
}
case SuspendedOnImmediate: {
workInProgressSuspendedReason = SuspendedAndReadyToContinue;
break outer;
}
case SuspendedOnInstance: {
workInProgressSuspendedReason =
SuspendedOnInstanceAndReadyToContinue;
break outer;
}
case SuspendedAndReadyToContinue: {
const thenable: Thenable<mixed> = (thrownValue: any);
if (isThenableResolved(thenable)) {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
replaySuspendedUnitOfWork(unitOfWork);
} else {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedAndReadyToContinue,
);
}
break;
}
case SuspendedOnInstanceAndReadyToContinue: {
let resource: null | Resource = null;
switch (workInProgress.tag) {
case HostHoistable: {
resource = workInProgress.memoizedState;
}
case HostComponent:
case HostSingleton: {
const hostFiber = workInProgress;
const type = hostFiber.type;
const props = hostFiber.pendingProps;
const isReady = resource
? preloadResource(resource)
: preloadInstance(type, props);
if (isReady) {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
const sibling = hostFiber.sibling;
if (sibling !== null) {
workInProgress = sibling;
} else {
const returnFiber = hostFiber.return;
if (returnFiber !== null) {
workInProgress = returnFiber;
completeUnitOfWork(returnFiber);
} else {
workInProgress = null;
}
}
break resumeOrUnwind;
}
break;
}
default: {
if (__DEV__) {
console.error(
'Unexpected type of fiber triggered a suspensey commit. ' +
'This is a bug in React.',
);
}
break;
}
}
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedOnInstanceAndReadyToContinue,
);
break;
}
case SuspendedOnDeprecatedThrowPromise: {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedOnDeprecatedThrowPromise,
);
break;
}
case SuspendedOnHydration: {
resetWorkInProgressStack();
workInProgressRootExitStatus = RootDidNotComplete;
break outer;
}
default: {
throw new Error(
'Unexpected SuspendedReason. This is a bug in React.',
);
}
}
}
if (__DEV__ && ReactSharedInternals.actQueue !== null) {
workLoopSync();
} else {
workLoopConcurrent();
}
break;
} catch (thrownValue) {
handleThrow(root, thrownValue);
}
} while (true);
resetContextDependencies();
popDispatcher(prevDispatcher);
popAsyncDispatcher(prevAsyncDispatcher);
executionContext = prevExecutionContext;
if (__DEV__) {
if (enableDebugTracing) {
logRenderStopped();
}
}
if (workInProgress !== null) {
if (enableSchedulingProfiler) {
markRenderYielded();
}
return RootInProgress;
} else {
if (enableSchedulingProfiler) {
markRenderStopped();
}
workInProgressRoot = null;
workInProgressRootRenderLanes = NoLanes;
finishQueueingConcurrentUpdates();
return workInProgressRootExitStatus;
}
}
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(unitOfWork: Fiber): void {
const current = unitOfWork.alternate;
let next;
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
startProfilerTimer(unitOfWork);
if (__DEV__) {
next = runWithFiberInDEV(
unitOfWork,
beginWork,
current,
unitOfWork,
entangledRenderLanes,
);
} else {
next = beginWork(current, unitOfWork, entangledRenderLanes);
}
stopProfilerTimerIfRunningAndRecordDuration(unitOfWork);
} else {
if (__DEV__) {
next = runWithFiberInDEV(
unitOfWork,
beginWork,
current,
unitOfWork,
entangledRenderLanes,
);
} else {
next = beginWork(current, unitOfWork, entangledRenderLanes);
}
}
if (!disableStringRefs) {
resetCurrentFiber();
}
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
}
function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
let next;
if (__DEV__) {
next = runWithFiberInDEV(unitOfWork, replayBeginWork, unitOfWork);
} else {
next = replayBeginWork(unitOfWork);
}
if (!disableStringRefs) {
resetCurrentFiber();
}
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
}
function replayBeginWork(unitOfWork: Fiber): null | Fiber {
const current = unitOfWork.alternate;
let next;
const isProfilingMode =
enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode;
if (isProfilingMode) {
startProfilerTimer(unitOfWork);
}
switch (unitOfWork.tag) {
case SimpleMemoComponent:
case FunctionComponent: {
const Component = unitOfWork.type;
const unresolvedProps = unitOfWork.pendingProps;
const resolvedProps =
disableDefaultPropsExceptForClasses ||
unitOfWork.elementType === Component
? unresolvedProps
: resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps);
let context: any;
if (!disableLegacyContext) {
const unmaskedContext = getUnmaskedContext(unitOfWork, Component, true);
context = getMaskedContext(unitOfWork, unmaskedContext);
}
next = replayFunctionComponent(
current,
unitOfWork,
resolvedProps,
Component,
context,
workInProgressRootRenderLanes,
);
break;
}
case ForwardRef: {
const Component = unitOfWork.type.render;
const unresolvedProps = unitOfWork.pendingProps;
const resolvedProps =
disableDefaultPropsExceptForClasses ||
unitOfWork.elementType === Component
? unresolvedProps
: resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps);
next = replayFunctionComponent(
current,
unitOfWork,
resolvedProps,
Component,
unitOfWork.ref,
workInProgressRootRenderLanes,
);
break;
}
case HostComponent: {
resetHooksOnUnwind(unitOfWork);
}
default: {
unwindInterruptedWork(current, unitOfWork, workInProgressRootRenderLanes);
unitOfWork = workInProgress = resetWorkInProgress(
unitOfWork,
entangledRenderLanes,
);
next = beginWork(current, unitOfWork, entangledRenderLanes);
break;
}
}
if (isProfilingMode) {
stopProfilerTimerIfRunningAndRecordDuration(unitOfWork);
}
return next;
}
function throwAndUnwindWorkLoop(
root: FiberRoot,
unitOfWork: Fiber,
thrownValue: mixed,
suspendedReason: SuspendedReason,
) {
resetSuspendedWorkLoopOnUnwind(unitOfWork);
const returnFiber = unitOfWork.return;
try {
const didFatal = throwException(
root,
returnFiber,
unitOfWork,
thrownValue,
workInProgressRootRenderLanes,
);
if (didFatal) {
panicOnRootError(root, thrownValue);
return;
}
} catch (error) {
if (returnFiber !== null) {
workInProgress = returnFiber;
throw error;
} else {
panicOnRootError(root, thrownValue);
return;
}
}
if (unitOfWork.flags & Incomplete) {
let skipSiblings;
if (!enableSiblingPrerendering) {
skipSiblings = true;
} else {
if (
getIsHydrating() ||
suspendedReason === SuspendedOnError
) {
skipSiblings = true;
} else if (
!workInProgressRootIsPrerendering &&
!includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
) {
skipSiblings = true;
workInProgressRootDidSkipSuspendedSiblings = true;
if (
suspendedReason === SuspendedOnData ||
suspendedReason === SuspendedOnImmediate ||
suspendedReason === SuspendedOnDeprecatedThrowPromise
) {
const boundary = getSuspenseHandler();
if (boundary !== null && boundary.tag === SuspenseComponent) {
boundary.flags |= ScheduleRetry;
}
}
} else {
skipSiblings = false;
}
}
unwindUnitOfWork(unitOfWork, skipSiblings);
} else {
completeUnitOfWork(unitOfWork);
}
}
export function markSpawnedRetryLane(lane: Lane): void {
workInProgressSuspendedRetryLanes = mergeLanes(
workInProgressSuspendedRetryLanes,
lane,
);
}
function panicOnRootError(root: FiberRoot, error: mixed) {
workInProgressRootExitStatus = RootFatalErrored;
logUncaughtError(root, createCapturedValueAtFiber(error, root.current));
workInProgress = null;
}
function completeUnitOfWork(unitOfWork: Fiber): void {
let completedWork: Fiber = unitOfWork;
do {
if ((completedWork.flags & Incomplete) !== NoFlags) {
const skipSiblings = workInProgressRootDidSkipSuspendedSiblings;
unwindUnitOfWork(completedWork, skipSiblings);
return;
}
const current = completedWork.alternate;
const returnFiber = completedWork.return;
let next;
startProfilerTimer(completedWork);
if (__DEV__) {
next = runWithFiberInDEV(
completedWork,
completeWork,
current,
completedWork,
entangledRenderLanes,
);
} else {
next = completeWork(current, completedWork, entangledRenderLanes);
}
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
stopProfilerTimerIfRunningAndRecordIncompleteDuration(completedWork);
}
if (next !== null) {
workInProgress = next;
return;
}
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
workInProgress = siblingFiber;
return;
}
completedWork = returnFiber;
workInProgress = completedWork;
} while (completedWork !== null);
if (workInProgressRootExitStatus === RootInProgress) {
workInProgressRootExitStatus = RootCompleted;
}
}
function unwindUnitOfWork(unitOfWork: Fiber, skipSiblings: boolean): void {
let incompleteWork: Fiber = unitOfWork;
do {
const current = incompleteWork.alternate;
const next = unwindWork(current, incompleteWork, entangledRenderLanes);
if (next !== null) {
next.flags &= HostEffectMask;
workInProgress = next;
return;
}
if (enableProfilerTimer && (incompleteWork.mode & ProfileMode) !== NoMode) {
stopProfilerTimerIfRunningAndRecordIncompleteDuration(incompleteWork);
let actualDuration = incompleteWork.actualDuration;
let child = incompleteWork.child;
while (child !== null) {
actualDuration += child.actualDuration;
child = child.sibling;
}
incompleteWork.actualDuration = actualDuration;
}
const returnFiber = incompleteWork.return;
if (returnFiber !== null) {
returnFiber.flags |= Incomplete;
returnFiber.subtreeFlags = NoFlags;
returnFiber.deletions = null;
}
if (!skipSiblings) {
const siblingFiber = incompleteWork.sibling;
if (siblingFiber !== null) {
workInProgress = siblingFiber;
return;
}
}
incompleteWork = returnFiber;
workInProgress = incompleteWork;
} while (incompleteWork !== null);
workInProgressRootExitStatus = RootDidNotComplete;
workInProgress = null;
}
type SuspendedCommitReason = 0 | 1 | 2;
const IMMEDIATE_COMMIT = 0;
const SUSPENDED_COMMIT = 1;
const THROTTLED_COMMIT = 2;
function commitRoot(
root: FiberRoot,
recoverableErrors: null | Array<CapturedValue<mixed>>,
transitions: Array<Transition> | null,
didIncludeRenderPhaseUpdate: boolean,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
suspendedCommitReason: SuspendedCommitReason,
completedRenderStartTime: number,
completedRenderEndTime: number,
) {
const prevTransition = ReactSharedInternals.T;
const previousUpdateLanePriority = getCurrentUpdatePriority();
try {
setCurrentUpdatePriority(DiscreteEventPriority);
ReactSharedInternals.T = null;
commitRootImpl(
root,
recoverableErrors,
transitions,
didIncludeRenderPhaseUpdate,
previousUpdateLanePriority,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
suspendedCommitReason,
completedRenderStartTime,
completedRenderEndTime,
);
} finally {
ReactSharedInternals.T = prevTransition;
setCurrentUpdatePriority(previousUpdateLanePriority);
}
}
function commitRootImpl(
root: FiberRoot,
recoverableErrors: null | Array<CapturedValue<mixed>>,
transitions: Array<Transition> | null,
didIncludeRenderPhaseUpdate: boolean,
renderPriorityLevel: EventPriority,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
suspendedCommitReason: SuspendedCommitReason,
completedRenderStartTime: number,
completedRenderEndTime: number,
) {
do {
flushPassiveEffects();
} while (rootWithPendingPassiveEffects !== null);
flushRenderPhaseStrictModeWarningsInDEV();
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.');
}
const finishedWork = root.finishedWork;
const lanes = root.finishedLanes;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logRenderPhase(completedRenderStartTime, completedRenderEndTime);
}
if (__DEV__) {
if (enableDebugTracing) {
logCommitStarted(lanes);
}
}
if (enableSchedulingProfiler) {
markCommitStarted(lanes);
}
if (finishedWork === null) {
if (__DEV__) {
if (enableDebugTracing) {
logCommitStopped();
}
}
if (enableSchedulingProfiler) {
markCommitStopped();
}
return null;
} else {
if (__DEV__) {
if (lanes === NoLanes) {
console.error(
'root.finishedLanes should not be empty during a commit. This is a ' +
'bug in React.',
);
}
}
}
root.finishedWork = null;
root.finishedLanes = NoLanes;
if (finishedWork === root.current) {
throw new Error(
'Cannot commit the same tree as before. This error is likely caused by ' +
'a bug in React. Please file an issue.',
);
}
root.callbackNode = null;
root.callbackPriority = NoLane;
root.cancelPendingCommit = null;
let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();
remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes);
markRootFinished(
root,
lanes,
remainingLanes,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
);
didIncludeCommitPhaseUpdate = false;
if (root === workInProgressRoot) {
workInProgressRoot = null;
workInProgress = null;
workInProgressRootRenderLanes = NoLanes;
} else {
}
if (
(enableProfilerTimer &&
enableComponentPerformanceTrack &&
finishedWork.actualDuration !== 0) ||
(finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||
(finishedWork.flags & PassiveMask) !== NoFlags
) {
if (!rootDoesHavePassiveEffects) {
rootDoesHavePassiveEffects = true;
pendingPassiveEffectsRemainingLanes = remainingLanes;
pendingPassiveEffectsRenderEndTime = completedRenderEndTime;
pendingPassiveTransitions = transitions;
scheduleCallback(NormalSchedulerPriority, () => {
flushPassiveEffects(true);
return null;
});
}
}
if (enableProfilerTimer) {
recordCommitTime();
if (enableComponentPerformanceTrack) {
if (suspendedCommitReason === SUSPENDED_COMMIT) {
logSuspendedCommitPhase(completedRenderEndTime, commitStartTime);
} else if (suspendedCommitReason === THROTTLED_COMMIT) {
logSuspenseThrottlePhase(completedRenderEndTime, commitStartTime);
}
}
}
const subtreeHasEffects =
(finishedWork.subtreeFlags &
(BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
NoFlags;
const rootHasEffect =
(finishedWork.flags &
(BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
NoFlags;
if (subtreeHasEffects || rootHasEffect) {
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(
root,
finishedWork,
);
commitMutationEffects(root, finishedWork, lanes);
if (enableCreateEventHandleAPI) {
if (shouldFireAfterActiveInstanceBlur) {
afterActiveInstanceBlur();
}
}
resetAfterCommit(root.containerInfo);
root.current = finishedWork;
if (__DEV__) {
if (enableDebugTracing) {
logLayoutEffectsStarted(lanes);
}
}
if (enableSchedulingProfiler) {
markLayoutEffectsStarted(lanes);
}
commitLayoutEffects(finishedWork, root, lanes);
if (__DEV__) {
if (enableDebugTracing) {
logLayoutEffectsStopped();
}
}
if (enableSchedulingProfiler) {
markLayoutEffectsStopped();
}
requestPaint();
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
} else {
root.current = finishedWork;
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
recordCommitEndTime();
logCommitPhase(commitStartTime, commitEndTime);
}
const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;
if (rootDoesHavePassiveEffects) {
rootDoesHavePassiveEffects = false;
rootWithPendingPassiveEffects = root;
pendingPassiveEffectsLanes = lanes;
} else {
releaseRootPooledCache(root, remainingLanes);
if (__DEV__) {
nestedPassiveUpdateCount = 0;
rootWithPassiveNestedUpdates = null;
}
}
remainingLanes = root.pendingLanes;
if (remainingLanes === NoLanes) {
legacyErrorBoundariesThatAlreadyFailed = null;
}
if (__DEV__) {
if (!rootDidHavePassiveEffects) {
commitDoubleInvokeEffectsInDEV(root, false);
}
}
onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
root.memoizedUpdaters.clear();
}
}
if (__DEV__) {
onCommitRootTestSelector();
}
ensureRootIsScheduled(root);
if (recoverableErrors !== null) {
const onRecoverableError = root.onRecoverableError;
for (let i = 0; i < recoverableErrors.length; i++) {
const recoverableError = recoverableErrors[i];
const errorInfo = makeErrorInfo(recoverableError.stack);
if (__DEV__) {
runWithFiberInDEV(
recoverableError.source,
onRecoverableError,
recoverableError.value,
errorInfo,
);
} else {
onRecoverableError(recoverableError.value, errorInfo);
}
}
}
if (
includesSyncLane(pendingPassiveEffectsLanes) &&
(disableLegacyMode || root.tag !== LegacyRoot)
) {
flushPassiveEffects();
}
remainingLanes = root.pendingLanes;
if (
(enableInfiniteRenderLoopDetection &&
(didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) ||
(includesSomeLane(lanes, UpdateLanes) &&
includesSomeLane(remainingLanes, SyncUpdateLanes))
) {
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
markNestedUpdateScheduled();
}
if (root === rootWithNestedUpdates) {
nestedUpdateCount++;
} else {
nestedUpdateCount = 0;
rootWithNestedUpdates = root;
}
} else {
nestedUpdateCount = 0;
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (!rootDidHavePassiveEffects) {
finalizeRender(lanes, now());
}
}
flushSyncWorkOnAllRoots();
if (__DEV__) {
if (enableDebugTracing) {
logCommitStopped();
}
}
if (enableSchedulingProfiler) {
markCommitStopped();
}
if (enableTransitionTracing) {
const prevRootTransitionCallbacks = root.transitionCallbacks;
if (prevRootTransitionCallbacks !== null) {
schedulePostPaintCallback(endTime => {
const prevPendingTransitionCallbacks =
currentPendingTransitionCallbacks;
if (prevPendingTransitionCallbacks !== null) {
currentPendingTransitionCallbacks = null;
scheduleCallback(IdleSchedulerPriority, () => {
processTransitionCallbacks(
prevPendingTransitionCallbacks,
endTime,
prevRootTransitionCallbacks,
);
});
} else {
currentEndTime = endTime;
}
});
}
}
return null;
}
function makeErrorInfo(componentStack: ?string) {
const errorInfo = {
componentStack,
};
if (__DEV__) {
Object.defineProperty((errorInfo: any), 'digest', {
get() {
console.error(
'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' +
' This property is no longer provided as part of errorInfo but can be accessed as a property' +
' of the Error instance itself.',
);
},
});
}
return errorInfo;
}
function releaseRootPooledCache(root: FiberRoot, remainingLanes: Lanes) {
if (enableCache) {
const pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes);
if (pooledCacheLanes === NoLanes) {
const pooledCache = root.pooledCache;
if (pooledCache != null) {
root.pooledCache = null;
releaseCache(pooledCache);
}
}
}
}
export function flushPassiveEffects(wasDelayedCommit?: boolean): boolean {
if (rootWithPendingPassiveEffects !== null) {
const root = rootWithPendingPassiveEffects;
const remainingLanes = pendingPassiveEffectsRemainingLanes;
pendingPassiveEffectsRemainingLanes = NoLanes;
const renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes);
const priority = lowerEventPriority(DefaultEventPriority, renderPriority);
const prevTransition = ReactSharedInternals.T;
const previousPriority = getCurrentUpdatePriority();
try {
setCurrentUpdatePriority(priority);
ReactSharedInternals.T = null;
return flushPassiveEffectsImpl(wasDelayedCommit);
} finally {
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
releaseRootPooledCache(root, remainingLanes);
}
}
return false;
}
function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) {
if (rootWithPendingPassiveEffects === null) {
return false;
}
const transitions = pendingPassiveTransitions;
pendingPassiveTransitions = null;
const root = rootWithPendingPassiveEffects;
const lanes = pendingPassiveEffectsLanes;
rootWithPendingPassiveEffects = null;
pendingPassiveEffectsLanes = NoLanes;
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Cannot flush passive effects while already rendering.');
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
}
if (__DEV__) {
isFlushingPassiveEffects = true;
didScheduleUpdateDuringPassiveEffects = false;
if (enableDebugTracing) {
logPassiveEffectsStarted(lanes);
}
}
let passiveEffectStartTime = 0;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
passiveEffectStartTime = now();
logPaintYieldPhase(commitEndTime, passiveEffectStartTime);
}
if (enableSchedulingProfiler) {
markPassiveEffectsStarted(lanes);
}
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
commitPassiveUnmountEffects(root.current);
commitPassiveMountEffects(
root,
root.current,
lanes,
transitions,
pendingPassiveEffectsRenderEndTime,
);
if (__DEV__) {
if (enableDebugTracing) {
logPassiveEffectsStopped();
}
}
if (enableSchedulingProfiler) {
markPassiveEffectsStopped();
}
if (__DEV__) {
commitDoubleInvokeEffectsInDEV(root, true);
}
executionContext = prevExecutionContext;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
const passiveEffectsEndTime = now();
if (wasDelayedCommit) {
logPassiveCommitPhase(passiveEffectStartTime, passiveEffectsEndTime);
}
finalizeRender(lanes, passiveEffectsEndTime);
}
flushSyncWorkOnAllRoots();
if (enableTransitionTracing) {
const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
const prevRootTransitionCallbacks = root.transitionCallbacks;
const prevEndTime = currentEndTime;
if (
prevPendingTransitionCallbacks !== null &&
prevRootTransitionCallbacks !== null &&
prevEndTime !== null
) {
currentPendingTransitionCallbacks = null;
currentEndTime = null;
scheduleCallback(IdleSchedulerPriority, () => {
processTransitionCallbacks(
prevPendingTransitionCallbacks,
prevEndTime,
prevRootTransitionCallbacks,
);
});
}
}
if (__DEV__) {
if (didScheduleUpdateDuringPassiveEffects) {
if (root === rootWithPassiveNestedUpdates) {
nestedPassiveUpdateCount++;
} else {
nestedPassiveUpdateCount = 0;
rootWithPassiveNestedUpdates = root;
}
} else {
nestedPassiveUpdateCount = 0;
}
isFlushingPassiveEffects = false;
didScheduleUpdateDuringPassiveEffects = false;
}
onPostCommitRootDevTools(root);
if (enableProfilerTimer && enableProfilerCommitHooks) {
const stateNode = root.current.stateNode;
stateNode.effectDuration = 0;
stateNode.passiveEffectDuration = 0;
}
return true;
}
export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {
return (
legacyErrorBoundariesThatAlreadyFailed !== null &&
legacyErrorBoundariesThatAlreadyFailed.has(instance)
);
}
export function markLegacyErrorBoundaryAsFailed(instance: mixed) {
if (legacyErrorBoundariesThatAlreadyFailed === null) {
legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);
} else {
legacyErrorBoundariesThatAlreadyFailed.add(instance);
}
}
function captureCommitPhaseErrorOnRoot(
rootFiber: Fiber,
sourceFiber: Fiber,
error: mixed,
) {
const errorInfo = createCapturedValueAtFiber(error, sourceFiber);
const update = createRootErrorUpdate(
rootFiber.stateNode,
errorInfo,
(SyncLane: Lane),
);
const root = enqueueUpdate(rootFiber, update, (SyncLane: Lane));
if (root !== null) {
markRootUpdated(root, SyncLane);
ensureRootIsScheduled(root);
}
}
export function captureCommitPhaseError(
sourceFiber: Fiber,
nearestMountedAncestor: Fiber | null,
error: mixed,
) {
if (__DEV__) {
setIsRunningInsertionEffect(false);
}
if (sourceFiber.tag === HostRoot) {
captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);
return;
}
let fiber = nearestMountedAncestor;
while (fiber !== null) {
if (fiber.tag === HostRoot) {
captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);
return;
} else if (fiber.tag === ClassComponent) {
const ctor = fiber.type;
const instance = fiber.stateNode;
if (
typeof ctor.getDerivedStateFromError === 'function' ||
(typeof instance.componentDidCatch === 'function' &&
!isAlreadyFailedLegacyErrorBoundary(instance))
) {
const errorInfo = createCapturedValueAtFiber(error, sourceFiber);
const update = createClassErrorUpdate((SyncLane: Lane));
const root = enqueueUpdate(fiber, update, (SyncLane: Lane));
if (root !== null) {
initializeClassErrorUpdate(update, root, fiber, errorInfo);
markRootUpdated(root, SyncLane);
ensureRootIsScheduled(root);
}
return;
}
}
fiber = fiber.return;
}
if (__DEV__) {
console.error(
'Internal React error: Attempted to capture a commit phase error ' +
'inside a detached tree. This indicates a bug in React. Potential ' +
'causes include deleting the same fiber more than once, committing an ' +
'already-finished tree, or an inconsistent return pointer.\n\n' +
'Error message:\n\n%s',
error,
);
}
}
export function attachPingListener(
root: FiberRoot,
wakeable: Wakeable,
lanes: Lanes,
) {
let pingCache = root.pingCache;
let threadIDs;
if (pingCache === null) {
pingCache = root.pingCache = new PossiblyWeakMap();
threadIDs = new Set<mixed>();
pingCache.set(wakeable, threadIDs);
} else {
threadIDs = pingCache.get(wakeable);
if (threadIDs === undefined) {
threadIDs = new Set();
pingCache.set(wakeable, threadIDs);
}
}
if (!threadIDs.has(lanes)) {
workInProgressRootDidAttachPingListener = true;
threadIDs.add(lanes);
const ping = pingSuspendedRoot.bind(null, root, wakeable, lanes);
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
restorePendingUpdaters(root, lanes);
}
}
wakeable.then(ping, ping);
}
}
function pingSuspendedRoot(
root: FiberRoot,
wakeable: Wakeable,
pingedLanes: Lanes,
) {
const pingCache = root.pingCache;
if (pingCache !== null) {
pingCache.delete(wakeable);
}
markRootPinged(root, pingedLanes);
warnIfSuspenseResolutionNotWrappedWithActDEV(root);
if (
workInProgressRoot === root &&
isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)
) {
if (
workInProgressRootExitStatus === RootSuspendedWithDelay ||
(workInProgressRootExitStatus === RootSuspended &&
includesOnlyRetries(workInProgressRootRenderLanes) &&
now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)
) {
if ((executionContext & RenderContext) === NoContext) {
prepareFreshStack(root, NoLanes);
} else {
}
} else {
workInProgressRootPingedLanes = mergeLanes(
workInProgressRootPingedLanes,
pingedLanes,
);
}
if (workInProgressSuspendedRetryLanes === workInProgressRootRenderLanes) {
workInProgressSuspendedRetryLanes = NoLanes;
}
}
ensureRootIsScheduled(root);
}
function retryTimedOutBoundary(boundaryFiber: Fiber, retryLane: Lane) {
if (retryLane === NoLane) {
retryLane = requestRetryLane(boundaryFiber);
}
const root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane);
if (root !== null) {
markRootUpdated(root, retryLane);
ensureRootIsScheduled(root);
}
}
export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {
const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
let retryLane: Lane = NoLane;
if (suspenseState !== null) {
retryLane = suspenseState.retryLane;
}
retryTimedOutBoundary(boundaryFiber, retryLane);
}
export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {
let retryLane: Lane = NoLane;
let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;
switch (boundaryFiber.tag) {
case SuspenseComponent:
retryCache = boundaryFiber.stateNode;
const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;
if (suspenseState !== null) {
retryLane = suspenseState.retryLane;
}
break;
case SuspenseListComponent:
retryCache = boundaryFiber.stateNode;
break;
case OffscreenComponent: {
const instance: OffscreenInstance = boundaryFiber.stateNode;
retryCache = instance._retryCache;
break;
}
default:
throw new Error(
'Pinged unknown suspense boundary type. ' +
'This is probably a bug in React.',
);
}
if (retryCache !== null) {
retryCache.delete(wakeable);
}
retryTimedOutBoundary(boundaryFiber, retryLane);
}
export function throwIfInfiniteUpdateLoopDetected() {
if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
nestedUpdateCount = 0;
nestedPassiveUpdateCount = 0;
rootWithNestedUpdates = null;
rootWithPassiveNestedUpdates = null;
if (enableInfiniteRenderLoopDetection) {
if (executionContext & RenderContext && workInProgressRoot !== null) {
workInProgressRoot.errorRecoveryDisabledLanes = mergeLanes(
workInProgressRoot.errorRecoveryDisabledLanes,
workInProgressRootRenderLanes,
);
}
}
throw new 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.',
);
}
if (__DEV__) {
if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {
nestedPassiveUpdateCount = 0;
rootWithPassiveNestedUpdates = null;
console.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.',
);
}
}
}
function flushRenderPhaseStrictModeWarningsInDEV() {
if (__DEV__) {
ReactStrictModeWarnings.flushLegacyContextWarning();
ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();
}
}
function recursivelyTraverseAndDoubleInvokeEffectsInDEV(
root: FiberRoot,
parentFiber: Fiber,
isInStrictMode: boolean,
) {
if ((parentFiber.subtreeFlags & (PlacementDEV | Visibility)) === NoFlags) {
return;
}
let child = parentFiber.child;
while (child !== null) {
doubleInvokeEffectsInDEVIfNecessary(root, child, isInStrictMode);
child = child.sibling;
}
}
function doubleInvokeEffectsOnFiber(
root: FiberRoot,
fiber: Fiber,
shouldDoubleInvokePassiveEffects: boolean = true,
) {
setIsStrictModeForDevtools(true);
disappearLayoutEffects(fiber);
if (shouldDoubleInvokePassiveEffects) {
disconnectPassiveEffect(fiber);
}
reappearLayoutEffects(root, fiber.alternate, fiber, false);
if (shouldDoubleInvokePassiveEffects) {
reconnectPassiveEffects(root, fiber, NoLanes, null, false);
}
setIsStrictModeForDevtools(false);
}
function doubleInvokeEffectsInDEVIfNecessary(
root: FiberRoot,
fiber: Fiber,
parentIsInStrictMode: boolean,
) {
const isStrictModeFiber = fiber.type === REACT_STRICT_MODE_TYPE;
const isInStrictMode = parentIsInStrictMode || isStrictModeFiber;
if (fiber.tag !== OffscreenComponent) {
if (fiber.flags & PlacementDEV) {
if (isInStrictMode) {
runWithFiberInDEV(
fiber,
doubleInvokeEffectsOnFiber,
root,
fiber,
(fiber.mode & NoStrictPassiveEffectsMode) === NoMode,
);
}
} else {
recursivelyTraverseAndDoubleInvokeEffectsInDEV(
root,
fiber,
isInStrictMode,
);
}
return;
}
if (fiber.memoizedState === null) {
if (isInStrictMode && fiber.flags & Visibility) {
runWithFiberInDEV(fiber, doubleInvokeEffectsOnFiber, root, fiber);
} else if (fiber.subtreeFlags & PlacementDEV) {
runWithFiberInDEV(
fiber,
recursivelyTraverseAndDoubleInvokeEffectsInDEV,
root,
fiber,
isInStrictMode,
);
}
}
}
function commitDoubleInvokeEffectsInDEV(
root: FiberRoot,
hasPassiveEffects: boolean,
) {
if (__DEV__) {
if (useModernStrictMode && (disableLegacyMode || root.tag !== LegacyRoot)) {
let doubleInvokeEffects = true;
if (
(disableLegacyMode || root.tag === ConcurrentRoot) &&
!(root.current.mode & (StrictLegacyMode | StrictEffectsMode))
) {
doubleInvokeEffects = false;
}
recursivelyTraverseAndDoubleInvokeEffectsInDEV(
root,
root.current,
doubleInvokeEffects,
);
} else {
runWithFiberInDEV(
root.current,
legacyCommitDoubleInvokeEffectsInDEV,
root.current,
hasPassiveEffects,
);
}
}
}
function legacyCommitDoubleInvokeEffectsInDEV(
fiber: Fiber,
hasPassiveEffects: boolean,
) {
invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);
if (hasPassiveEffects) {
invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV);
}
invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV);
if (hasPassiveEffects) {
invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);
}
}
function invokeEffectsInDev(
firstChild: Fiber,
fiberFlags: Flags,
invokeEffectFn: (fiber: Fiber) => void,
) {
let current: null | Fiber = firstChild;
let subtreeRoot = null;
while (current != null) {
const primarySubtreeFlag = current.subtreeFlags & fiberFlags;
if (
current !== subtreeRoot &&
current.child != null &&
primarySubtreeFlag !== NoFlags
) {
current = current.child;
} else {
if ((current.flags & fiberFlags) !== NoFlags) {
invokeEffectFn(current);
}
if (current.sibling !== null) {
current = current.sibling;
} else {
current = subtreeRoot = current.return;
}
}
}
}
let didWarnStateUpdateForNotYetMountedComponent: Set<string> | null = null;
export function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber: Fiber) {
if (__DEV__) {
if ((executionContext & RenderContext) !== NoContext) {
return;
}
if (!disableLegacyMode && !(fiber.mode & ConcurrentMode)) {
return;
}
const tag = fiber.tag;
if (
tag !== HostRoot &&
tag !== ClassComponent &&
tag !== FunctionComponent &&
tag !== ForwardRef &&
tag !== MemoComponent &&
tag !== SimpleMemoComponent
) {
return;
}
const componentName = getComponentNameFromFiber(fiber) || 'ReactComponent';
if (didWarnStateUpdateForNotYetMountedComponent !== null) {
if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {
return;
}
didWarnStateUpdateForNotYetMountedComponent.add(componentName);
} else {
didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);
}
runWithFiberInDEV(fiber, () => {
console.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.',
);
});
}
}
let didWarnAboutUpdateInRender = false;
let didWarnAboutUpdateInRenderForAnotherComponent;
if (__DEV__) {
didWarnAboutUpdateInRenderForAnotherComponent = new Set<string>();
}
function warnAboutRenderPhaseUpdatesInDEV(fiber: Fiber) {
if (__DEV__) {
if (ReactCurrentDebugFiberIsRenderingInDEV) {
switch (fiber.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent: {
const renderingComponentName =
(workInProgress && getComponentNameFromFiber(workInProgress)) ||
'Unknown';
const dedupeKey = renderingComponentName;
if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {
didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);
const setStateComponentName =
getComponentNameFromFiber(fiber) || 'Unknown';
console.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://react.dev/link/setstate-in-render',
setStateComponentName,
renderingComponentName,
renderingComponentName,
);
}
break;
}
case ClassComponent: {
if (!didWarnAboutUpdateInRender) {
console.error(
'Cannot update during an existing state transition (such as ' +
'within `render`). Render methods should be a pure ' +
'function of props and state.',
);
didWarnAboutUpdateInRender = true;
}
break;
}
}
}
}
}
export function restorePendingUpdaters(root: FiberRoot, lanes: Lanes): void {
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
const memoizedUpdaters = root.memoizedUpdaters;
memoizedUpdaters.forEach(schedulingFiber => {
addFiberToLanesMap(root, schedulingFiber, lanes);
});
}
}
}
const fakeActCallbackNode = {};
function scheduleCallback(priorityLevel: any, callback) {
if (__DEV__) {
const actQueue = ReactSharedInternals.actQueue;
if (actQueue !== null) {
actQueue.push(callback);
return fakeActCallbackNode;
} else {
return Scheduler_scheduleCallback(priorityLevel, callback);
}
} else {
return Scheduler_scheduleCallback(priorityLevel, callback);
}
}
function shouldForceFlushFallbacksInDEV() {
return __DEV__ && ReactSharedInternals.actQueue !== null;
}
function warnIfUpdatesNotWrappedWithActDEV(fiber: Fiber): void {
if (__DEV__) {
if (disableLegacyMode || fiber.mode & ConcurrentMode) {
if (!isConcurrentActEnvironment()) {
return;
}
} else {
if (!isLegacyActEnvironment(fiber)) {
return;
}
if (executionContext !== NoContext) {
return;
}
if (
fiber.tag !== FunctionComponent &&
fiber.tag !== ForwardRef &&
fiber.tag !== SimpleMemoComponent
) {
return;
}
}
if (ReactSharedInternals.actQueue === null) {
runWithFiberInDEV(fiber, () => {
console.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://react.dev/link/wrap-tests-with-act',
getComponentNameFromFiber(fiber),
);
});
}
}
}
function warnIfSuspenseResolutionNotWrappedWithActDEV(root: FiberRoot): void {
if (__DEV__) {
if (
(disableLegacyMode || root.tag !== LegacyRoot) &&
isConcurrentActEnvironment() &&
ReactSharedInternals.actQueue === null
) {
console.error(
'A suspended resource finished loading inside a test, but the event ' +
'was not wrapped in act(...).\n\n' +
'When testing, code that resolves suspended data should be wrapped ' +
'into act(...):\n\n' +
'act(() => {\n' +
' /* finish loading suspended data */\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://react.dev/link/wrap-tests-with-act',
);
}
}
}
export function setIsRunningInsertionEffect(isRunning: boolean): void {
if (__DEV__) {
isRunningInsertionEffect = isRunning;
}
}