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 {ActivityState} from './ReactFiberActivityComponent';
import type {SuspenseState} from './ReactFiberSuspenseComponent';
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
import type {Transition} from 'react/src/ReactStartTransition';
import type {
PendingTransitionCallbacks,
PendingBoundaries,
TransitionAbort,
} from './ReactFiberTracingMarkerComponent';
import type {OffscreenInstance} from './ReactFiberOffscreenComponent';
import type {
Resource,
ViewTransitionInstance,
RunningViewTransition,
} from './ReactFiberConfig';
import type {RootState} from './ReactFiberRoot';
import {
getViewTransitionName,
type ViewTransitionState,
} from './ReactFiberViewTransitionComponent';
import type {TransitionTypes} from 'react/src/ReactTransitionType';
import {
enableCreateEventHandleAPI,
enableProfilerTimer,
enableProfilerCommitHooks,
enableProfilerNestedUpdatePhase,
enableSchedulingProfiler,
enableUpdaterTracking,
enableTransitionTracing,
disableLegacyContext,
alwaysThrottleRetries,
enableInfiniteRenderLoopDetection,
disableLegacyMode,
enableComponentPerformanceTrack,
enableYieldingBeforePassive,
enableThrottledScheduling,
enableViewTransition,
enableGestureTransition,
enableDefaultTransitionIndicator,
} from 'shared/ReactFeatureFlags';
import {resetOwnerStackLimit} from 'shared/ReactOwnerStackReset';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import is from 'shared/objectIs';
import reportGlobalError from 'shared/reportGlobalError';
import {
scheduleCallback as Scheduler_scheduleCallback,
shouldYield,
requestPaint,
now,
NormalPriority as NormalSchedulerPriority,
IdlePriority as IdleSchedulerPriority,
} from './Scheduler';
import {
logBlockingStart,
logTransitionStart,
logRenderPhase,
logInterruptedRenderPhase,
logSuspendedRenderPhase,
logRecoveredRenderPhase,
logErroredRenderPhase,
logInconsistentRender,
logSuspendedWithDelayPhase,
logSuspenseThrottlePhase,
logSuspendedCommitPhase,
logCommitPhase,
logPaintYieldPhase,
logPassiveCommitPhase,
logYieldTime,
logActionYieldTime,
logSuspendedYieldTime,
setCurrentTrackFromLanes,
markAllLanesInOrder,
} from './ReactFiberPerformanceTrack';
import {
resetAfterCommit,
scheduleTimeout,
cancelTimeout,
noTimeout,
afterActiveInstanceBlur,
startSuspendingCommit,
suspendOnActiveViewTransition,
waitForCommitToBeReady,
preloadInstance,
preloadResource,
supportsHydration,
setCurrentUpdatePriority,
getCurrentUpdatePriority,
resolveUpdatePriority,
trackSchedulerEvent,
startViewTransition,
startGestureTransition,
stopViewTransition,
createViewTransitionInstance,
flushHydrationEvents,
} from './ReactFiberConfig';
import {createWorkInProgress, resetWorkInProgress} from './ReactFiber';
import {isRootDehydrated} from './ReactFiberShellHydration';
import {getIsHydrating} from './ReactFiberHydrationContext';
import {
NoMode,
ProfileMode,
ConcurrentMode,
StrictLegacyMode,
StrictEffectsMode,
} from './ReactTypeOfMode';
import {
HostRoot,
ClassComponent,
ActivityComponent,
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,
PassiveTransitionMask,
} 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,
includesOnlyViewTransitionEligibleLanes,
isGestureRender,
GestureLane,
} 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,
shouldFireAfterActiveInstanceBlur,
commitAfterMutationEffects,
commitLayoutEffects,
commitMutationEffects,
commitPassiveMountEffects,
commitPassiveUnmountEffects,
disappearLayoutEffects,
reconnectPassiveEffects,
reappearLayoutEffects,
disconnectPassiveEffect,
invokeLayoutEffectMountInDEV,
invokePassiveEffectMountInDEV,
invokeLayoutEffectUnmountInDEV,
invokePassiveEffectUnmountInDEV,
accumulateSuspenseyCommit,
} from './ReactFiberCommitWork';
import {resetShouldStartViewTransition} from './ReactFiberCommitViewTransitions';
import {shouldStartViewTransition} from './ReactFiberCommitViewTransitions';
import {
insertDestinationClones,
applyDepartureTransitions,
startGestureAnimations,
} from './ReactFiberApplyGesture';
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 {
blockingClampTime,
blockingUpdateTime,
blockingUpdateTask,
blockingEventTime,
blockingEventType,
blockingEventIsRepeat,
blockingSpawnedUpdate,
blockingSuspendedTime,
transitionClampTime,
transitionStartTime,
transitionUpdateTime,
transitionUpdateTask,
transitionEventTime,
transitionEventType,
transitionEventIsRepeat,
transitionSuspendedTime,
clearBlockingTimers,
clearTransitionTimers,
clampBlockingTimers,
clampTransitionTimers,
markNestedUpdateScheduled,
renderStartTime,
commitStartTime,
commitEndTime,
commitErrors,
recordRenderTime,
recordCommitTime,
recordCommitEndTime,
startProfilerTimer,
stopProfilerTimerIfRunningAndRecordDuration,
stopProfilerTimerIfRunningAndRecordIncompleteDuration,
trackSuspendedTime,
startYieldTimer,
yieldStartTime,
yieldReason,
startPingTimerByLanes,
recordEffectError,
resetCommitErrors,
} from './ReactProfilerTimer';
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,
SuspenseActionException,
SuspenseyCommitException,
getSuspendedThenable,
isThenableResolved,
} from './ReactFiberThenable';
import {schedulePostPaintCallback} from './ReactPostPaintCallback';
import {
getSuspenseHandler,
getShellBoundary,
} from './ReactFiberSuspenseContext';
import {resetChildReconcilerOnUnwind} from './ReactChildFiber';
import {
ensureRootIsScheduled,
flushSyncWorkOnAllRoots,
flushSyncWorkOnLegacyRootsOnly,
requestTransitionLane,
} from './ReactFiberRootScheduler';
import {getMaskedContext, getUnmaskedContext} from './ReactFiberLegacyContext';
import {logUncaughtError} from './ReactFiberErrorLogger';
import {
deleteScheduledGesture,
stopCompletedGestures,
} from './ReactFiberGestureScheduler';
import {claimQueuedTransitionTypes} from './ReactFiberTransitionTypes';
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 RootSuspendedAtTheShell = 6;
const RootCompleted = 5;
let executionContext: ExecutionContext = NoContext;
let workInProgressRoot: FiberRoot | null = null;
let workInProgress: Fiber | null = null;
let workInProgressRootRenderLanes: Lanes = NoLanes;
export opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
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;
const SuspendedOnAction: SuspendedReason = 9;
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;
type SuspendedCommitReason = 0 | 1 | 2;
const IMMEDIATE_COMMIT = 0;
const SUSPENDED_COMMIT = 1;
const THROTTLED_COMMIT = 2;
const NO_PENDING_EFFECTS = 0;
const PENDING_MUTATION_PHASE = 1;
const PENDING_LAYOUT_PHASE = 2;
const PENDING_AFTER_MUTATION_PHASE = 3;
const PENDING_SPAWNED_WORK = 4;
const PENDING_PASSIVE_PHASE = 5;
const PENDING_GESTURE_MUTATION_PHASE = 6;
const PENDING_GESTURE_ANIMATION_PHASE = 7;
let pendingEffectsStatus: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 = 0;
let pendingEffectsRoot: FiberRoot = (null: any);
let pendingFinishedWork: Fiber = (null: any);
let pendingEffectsLanes: Lanes = NoLanes;
let pendingEffectsRemainingLanes: Lanes = NoLanes;
let pendingEffectsRenderEndTime: number = -0;
let pendingPassiveTransitions: Array<Transition> | null = null;
let pendingRecoverableErrors: null | Array<CapturedValue<mixed>> = null;
let pendingViewTransition: null | RunningViewTransition = null;
let pendingViewTransitionEvents: Array<(types: Array<string>) => void> | null =
null;
let pendingTransitionTypes: null | TransitionTypes = null;
let pendingDidIncludeRenderPhaseUpdate: boolean = false;
let pendingSuspendedCommitReason: SuspendedCommitReason = IMMEDIATE_COMMIT;
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 getCommittingRoot(): FiberRoot | null {
return pendingEffectsRoot;
}
export function getWorkInProgressRootRenderLanes(): Lanes {
return workInProgressRootRenderLanes;
}
export function hasPendingCommitEffects(): boolean {
return (
pendingEffectsStatus !== NO_PENDING_EFFECTS &&
pendingEffectsStatus !== PENDING_PASSIVE_PHASE
);
}
export function getRootWithPendingPassiveEffects(): FiberRoot | null {
return pendingEffectsStatus === PENDING_PASSIVE_PHASE
? pendingEffectsRoot
: null;
}
export function getPendingPassiveEffectsLanes(): Lanes {
return pendingEffectsLanes;
}
export function getPendingTransitionTypes(): null | TransitionTypes {
return pendingTransitionTypes;
}
export function isWorkLoopSuspendedOnData(): boolean {
return (
workInProgressSuspendedReason === SuspendedOnData ||
workInProgressSuspendedReason === SuspendedOnAction
);
}
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 (enableGestureTransition) {
if (transition.gesture) {
throw new Error(
'Cannot setState on regular state inside a startGestureTransition. ' +
'Gestures can only update the useOptimistic() hook. There should be no ' +
'side-effects associated with starting a Gesture until its Action is ' +
'invoked. Move side-effects to the Action instead.',
);
}
}
if (__DEV__) {
if (!transition._updatedFibers) {
transition._updatedFibers = new Set();
}
transition._updatedFibers.add(fiber);
}
return 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 scheduleViewTransitionEvent(
fiber: Fiber,
callback: ?(instance: ViewTransitionInstance, types: Array<string>) => void,
): void {
if (enableViewTransition) {
if (callback != null) {
const state: ViewTransitionState = fiber.stateNode;
let instance = state.ref;
if (instance === null) {
instance = state.ref = createViewTransitionInstance(
getViewTransitionName(fiber.memoizedProps, state),
);
}
if (pendingViewTransitionEvents === null) {
pendingViewTransitionEvents = [];
}
pendingViewTransitionEvents.push(callback.bind(null, instance));
}
}
}
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 ||
workInProgressSuspendedReason === SuspendedOnAction)) ||
root.cancelPendingCommit !== null
) {
prepareFreshStack(root, NoLanes);
const didAttemptEntireTree = false;
markRootSuspended(
root,
workInProgressRootRenderLanes,
workInProgressDeferredLane,
didAttemptEntireTree,
);
}
markRootUpdated(root, lane);
if (
(executionContext & RenderContext) !== NoContext &&
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) {
const didAttemptEntireTree = false;
markRootSuspended(
root,
workInProgressRootRenderLanes,
workInProgressDeferredLane,
didAttemptEntireTree,
);
}
}
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.');
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (workInProgressRootRenderLanes !== NoLanes && workInProgress !== null) {
const yieldedFiber = workInProgress;
const yieldEndTime = now();
switch (yieldReason) {
case SuspendedOnImmediate:
case SuspendedOnData:
logSuspendedYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);
break;
case SuspendedOnAction:
logActionYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);
break;
default:
logYieldTime(yieldStartTime, yieldEndTime);
}
}
}
const shouldTimeSlice =
(!forceSync &&
!includesBlockingLane(lanes) &&
!includesExpiredLane(root, lanes)) ||
checkIfRootIsPrerendering(root, lanes);
let exitStatus = shouldTimeSlice
? renderRootConcurrent(root, lanes)
: renderRootSync(root, lanes, true);
let renderWasConcurrent = shouldTimeSlice;
do {
if (exitStatus === RootInProgress) {
if (workInProgressRootIsPrerendering && !shouldTimeSlice) {
const didAttemptEntireTree = false;
markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
startYieldTimer(workInProgressSuspendedReason);
}
break;
} else {
let renderEndTime = 0;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
renderEndTime = now();
}
const finishedWork: Fiber = (root.current.alternate: any);
if (
renderWasConcurrent &&
!isRenderConsistentWithExternalStores(finishedWork)
) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logInconsistentRender(renderStartTime, renderEndTime);
finalizeRender(lanes, renderEndTime);
}
exitStatus = renderRootSync(root, lanes, false);
renderWasConcurrent = false;
continue;
}
if (
(disableLegacyMode || root.tag !== LegacyRoot) &&
exitStatus === RootErrored
) {
const lanesThatJustErrored = lanes;
const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
root,
lanesThatJustErrored,
);
if (errorRetryLanes !== NoLanes) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logErroredRenderPhase(renderStartTime, renderEndTime, lanes);
finalizeRender(lanes, renderEndTime);
}
lanes = errorRetryLanes;
exitStatus = recoverFromConcurrentError(
root,
lanesThatJustErrored,
errorRetryLanes,
);
renderWasConcurrent = false;
if (exitStatus !== RootErrored) {
continue;
} else {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
renderEndTime = now();
}
}
}
}
if (exitStatus === RootFatalErrored) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logErroredRenderPhase(renderStartTime, renderEndTime, lanes);
finalizeRender(lanes, renderEndTime);
}
prepareFreshStack(root, NoLanes);
const didAttemptEntireTree = true;
markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
break;
}
finishConcurrentRender(
root,
exitStatus,
finishedWork,
lanes,
renderEndTime,
);
}
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, false);
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,
renderEndTime: number,
) {
switch (exitStatus) {
case RootInProgress:
case RootFatalErrored: {
throw new Error('Root did not complete. This is a bug in React.');
}
case RootSuspendedWithDelay: {
if (!includesOnlyTransitions(lanes)) {
break;
}
}
case RootSuspendedAtTheShell: {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logSuspendedRenderPhase(renderStartTime, renderEndTime, lanes);
finalizeRender(lanes, renderEndTime);
trackSuspendedTime(lanes, renderEndTime);
}
const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings;
markRootSuspended(
root,
lanes,
workInProgressDeferredLane,
didAttemptEntireTree,
);
return;
}
case RootErrored: {
workInProgressRootRecoverableErrors = null;
break;
}
case RootSuspended:
case RootCompleted: {
break;
}
default: {
throw new Error('Unknown root exit status.');
}
}
if (shouldForceFlushFallbacksInDEV()) {
commitRoot(
root,
finishedWork,
lanes,
workInProgressRootRecoverableErrors,
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
workInProgressDeferredLane,
workInProgressRootInterleavedUpdatedLanes,
workInProgressSuspendedRetryLanes,
exitStatus,
IMMEDIATE_COMMIT,
renderStartTime,
renderEndTime,
);
} else {
if (
includesOnlyRetries(lanes) &&
(alwaysThrottleRetries || exitStatus === RootSuspended)
) {
const msUntilTimeout =
globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();
if (msUntilTimeout > 10) {
const didAttemptEntireTree =
!workInProgressRootDidSkipSuspendedSiblings;
markRootSuspended(
root,
lanes,
workInProgressDeferredLane,
didAttemptEntireTree,
);
const nextLanes = getNextLanes(root, NoLanes, true);
if (nextLanes !== NoLanes) {
return;
}
root.timeoutHandle = scheduleTimeout(
commitRootWhenReady.bind(
null,
root,
finishedWork,
workInProgressRootRecoverableErrors,
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
lanes,
workInProgressDeferredLane,
workInProgressRootInterleavedUpdatedLanes,
workInProgressSuspendedRetryLanes,
workInProgressRootDidSkipSuspendedSiblings,
exitStatus,
THROTTLED_COMMIT,
renderStartTime,
renderEndTime,
),
msUntilTimeout,
);
return;
}
}
commitRootWhenReady(
root,
finishedWork,
workInProgressRootRecoverableErrors,
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
lanes,
workInProgressDeferredLane,
workInProgressRootInterleavedUpdatedLanes,
workInProgressSuspendedRetryLanes,
workInProgressRootDidSkipSuspendedSiblings,
exitStatus,
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,
exitStatus: RootExitStatus,
suspendedCommitReason: SuspendedCommitReason,
completedRenderStartTime: number,
completedRenderEndTime: number,
) {
root.timeoutHandle = noTimeout;
const BothVisibilityAndMaySuspendCommit = Visibility | MaySuspendCommit;
const subtreeFlags = finishedWork.subtreeFlags;
const isViewTransitionEligible =
enableViewTransition && includesOnlyViewTransitionEligibleLanes(lanes);
const isGestureTransition = enableGestureTransition && isGestureRender(lanes);
const maySuspendCommit =
subtreeFlags & ShouldSuspendCommit ||
(subtreeFlags & BothVisibilityAndMaySuspendCommit) ===
BothVisibilityAndMaySuspendCommit;
if (isViewTransitionEligible || maySuspendCommit || isGestureTransition) {
startSuspendingCommit();
accumulateSuspenseyCommit(finishedWork, lanes);
if (isViewTransitionEligible || isGestureTransition) {
if (!enableGestureTransition || root.stoppingGestures === null) {
suspendOnActiveViewTransition(root.containerInfo);
}
}
const schedulePendingCommit = waitForCommitToBeReady();
if (schedulePendingCommit !== null) {
root.cancelPendingCommit = schedulePendingCommit(
commitRoot.bind(
null,
root,
finishedWork,
lanes,
recoverableErrors,
transitions,
didIncludeRenderPhaseUpdate,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
exitStatus,
SUSPENDED_COMMIT,
completedRenderStartTime,
completedRenderEndTime,
),
);
const didAttemptEntireTree = !didSkipSuspendedSiblings;
markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree);
return;
}
}
commitRoot(
root,
finishedWork,
lanes,
recoverableErrors,
transitions,
didIncludeRenderPhaseUpdate,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
exitStatus,
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,
didAttemptEntireTree: boolean,
) {
suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);
suspendedLanes = removeLanes(
suspendedLanes,
workInProgressRootInterleavedUpdatedLanes,
);
_markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree);
}
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 (
pendingEffectsStatus !== NO_PENDING_EFFECTS &&
!disableLegacyMode &&
pendingEffectsRoot.tag === LegacyRoot &&
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
flushPendingEffects();
}
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 (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) {
markAllLanesInOrder();
const previousRenderStartTime = renderStartTime;
recordRenderTime();
if (
workInProgressRootRenderLanes !== NoLanes &&
previousRenderStartTime > 0
) {
setCurrentTrackFromLanes(workInProgressRootRenderLanes);
if (
workInProgressRootExitStatus === RootSuspended ||
workInProgressRootExitStatus === RootSuspendedWithDelay
) {
logSuspendedRenderPhase(
previousRenderStartTime,
renderStartTime,
lanes,
);
} else {
logInterruptedRenderPhase(
previousRenderStartTime,
renderStartTime,
lanes,
);
}
finalizeRender(workInProgressRootRenderLanes, renderStartTime);
}
if (includesSyncLane(lanes) || includesBlockingLane(lanes)) {
const clampedUpdateTime =
blockingUpdateTime >= 0 && blockingUpdateTime < blockingClampTime
? blockingClampTime
: blockingUpdateTime;
const clampedEventTime =
blockingEventTime >= 0 && blockingEventTime < blockingClampTime
? blockingClampTime
: blockingEventTime;
if (blockingSuspendedTime >= 0) {
setCurrentTrackFromLanes(lanes);
logSuspendedWithDelayPhase(
blockingSuspendedTime,
clampedEventTime >= 0
? clampedEventTime
: clampedUpdateTime >= 0
? clampedUpdateTime
: renderStartTime,
lanes,
);
}
logBlockingStart(
clampedUpdateTime,
clampedEventTime,
blockingEventType,
blockingEventIsRepeat,
blockingSpawnedUpdate,
renderStartTime,
lanes,
blockingUpdateTask,
);
clearBlockingTimers();
}
if (includesTransitionLane(lanes)) {
const clampedStartTime =
transitionStartTime >= 0 && transitionStartTime < transitionClampTime
? transitionClampTime
: transitionStartTime;
const clampedUpdateTime =
transitionUpdateTime >= 0 && transitionUpdateTime < transitionClampTime
? transitionClampTime
: transitionUpdateTime;
const clampedEventTime =
transitionEventTime >= 0 && transitionEventTime < transitionClampTime
? transitionClampTime
: transitionEventTime;
if (transitionSuspendedTime >= 0) {
setCurrentTrackFromLanes(lanes);
logSuspendedWithDelayPhase(
transitionSuspendedTime,
clampedEventTime >= 0
? clampedEventTime
: clampedUpdateTime >= 0
? clampedUpdateTime
: renderStartTime,
lanes,
);
}
logTransitionStart(
clampedStartTime,
clampedUpdateTime,
clampedEventTime,
transitionEventType,
transitionEventIsRepeat,
renderStartTime,
transitionUpdateTask,
);
clearTransitionTimers();
}
}
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__) {
resetOwnerStackLimit();
ReactStrictModeWarnings.discardPendingWarnings();
}
return rootWorkInProgress;
}
function resetSuspendedWorkLoopOnUnwind(fiber: Fiber) {
resetContextDependencies();
resetHooksOnUnwind(fiber);
resetChildReconcilerOnUnwind();
}
function handleThrow(root: FiberRoot, thrownValue: any): void {
resetHooksAfterThrow();
if (__DEV__) {
resetCurrentFiber();
}
if (
thrownValue === SuspenseException ||
thrownValue === SuspenseActionException
) {
thrownValue = getSuspendedThenable();
workInProgressSuspendedReason = 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 SuspendedOnAction:
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() {
const prevAsyncDispatcher = ReactSharedInternals.A;
ReactSharedInternals.A = DefaultAsyncDispatcher;
return prevAsyncDispatcher;
}
function popAsyncDispatcher(prevAsyncDispatcher: any) {
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 &&
(includesOnlyTransitions(workInProgressRootRenderLanes) ||
getSuspenseHandler() === null)
) {
workInProgressRootIsPrerendering = true;
}
if (
(includesNonIdleWork(workInProgressRootSkippedLanes) ||
includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) &&
workInProgressRoot !== null
) {
const didAttemptEntireTree = false;
markRootSuspended(
workInProgressRoot,
workInProgressRootRenderLanes,
workInProgressDeferredLane,
didAttemptEntireTree,
);
}
}
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,
shouldYieldForPrerendering: boolean,
): RootExitStatus {
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 (enableSchedulingProfiler) {
markRenderStarted(lanes);
}
let didSuspendInShell = false;
let exitStatus = workInProgressRootExitStatus;
outer: do {
try {
if (
workInProgressSuspendedReason !== NotSuspended &&
workInProgress !== null
) {
const unitOfWork = workInProgress;
const thrownValue = workInProgressThrownValue;
switch (workInProgressSuspendedReason) {
case SuspendedOnHydration: {
resetWorkInProgressStack();
exitStatus = RootSuspendedAtTheShell;
break outer;
}
case SuspendedOnImmediate:
case SuspendedOnData:
case SuspendedOnAction:
case SuspendedOnDeprecatedThrowPromise: {
if (getSuspenseHandler() === null) {
didSuspendInShell = true;
}
const reason = workInProgressSuspendedReason;
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason);
if (
shouldYieldForPrerendering &&
workInProgressRootIsPrerendering
) {
exitStatus = RootInProgress;
break outer;
}
break;
}
default: {
const reason = workInProgressSuspendedReason;
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason);
break;
}
}
}
workLoopSync();
exitStatus = workInProgressRootExitStatus;
break;
} catch (thrownValue) {
handleThrow(root, thrownValue);
}
} while (true);
if (didSuspendInShell) {
root.shellSuspendCounter++;
}
resetContextDependencies();
executionContext = prevExecutionContext;
popDispatcher(prevDispatcher);
popAsyncDispatcher(prevAsyncDispatcher);
if (enableSchedulingProfiler) {
markRenderStopped();
}
if (workInProgress !== null) {
} else {
workInProgressRoot = null;
workInProgressRootRenderLanes = NoLanes;
finishQueueingConcurrentUpdates();
}
return exitStatus;
}
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 {
workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, 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:
case SuspendedOnAction: {
const thenable: Thenable<mixed> = (thrownValue: any);
if (isThenableResolved(thenable)) {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
replaySuspendedUnitOfWork(unitOfWork);
break;
}
const onResolution = () => {
if (
(workInProgressSuspendedReason === SuspendedOnData ||
workInProgressSuspendedReason === SuspendedOnAction) &&
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(hostFiber.stateNode, 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 = RootSuspendedAtTheShell;
break outer;
}
default: {
throw new Error(
'Unexpected SuspendedReason. This is a bug in React.',
);
}
}
}
if (__DEV__ && ReactSharedInternals.actQueue !== null) {
workLoopSync();
} else if (enableThrottledScheduling) {
workLoopConcurrent(includesNonIdleWork(lanes));
} else {
workLoopConcurrentByScheduler();
}
break;
} catch (thrownValue) {
handleThrow(root, thrownValue);
}
} while (true);
resetContextDependencies();
popDispatcher(prevDispatcher);
popAsyncDispatcher(prevAsyncDispatcher);
executionContext = prevExecutionContext;
if (workInProgress !== null) {
if (enableSchedulingProfiler) {
markRenderYielded();
}
return RootInProgress;
} else {
if (enableSchedulingProfiler) {
markRenderStopped();
}
workInProgressRoot = null;
workInProgressRootRenderLanes = NoLanes;
finishQueueingConcurrentUpdates();
return workInProgressRootExitStatus;
}
}
function workLoopConcurrent(nonIdle: boolean) {
if (workInProgress !== null) {
const yieldAfter = now() + (nonIdle ? 25 : 5);
do {
performUnitOfWork(workInProgress);
} while (workInProgress !== null && now() < yieldAfter);
}
}
function workLoopConcurrentByScheduler() {
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);
}
}
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);
}
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;
let context: any;
if (!disableLegacyContext) {
const unmaskedContext = getUnmaskedContext(unitOfWork, Component, true);
context = getMaskedContext(unitOfWork, unmaskedContext);
}
next = replayFunctionComponent(
current,
unitOfWork,
unitOfWork.pendingProps,
Component,
context,
workInProgressRootRenderLanes,
);
break;
}
case ForwardRef: {
const Component = unitOfWork.type.render;
next = replayFunctionComponent(
current,
unitOfWork,
unitOfWork.pendingProps,
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 (
getIsHydrating() ||
suspendedReason === SuspendedOnError
) {
skipSiblings = true;
} else if (
!workInProgressRootIsPrerendering &&
!includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
) {
skipSiblings = true;
workInProgressRootDidSkipSuspendedSiblings = true;
if (
suspendedReason === SuspendedOnData ||
suspendedReason === SuspendedOnAction ||
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 = RootSuspendedAtTheShell;
workInProgress = null;
}
function commitRoot(
root: FiberRoot,
finishedWork: null | Fiber,
lanes: Lanes,
recoverableErrors: null | Array<CapturedValue<mixed>>,
transitions: Array<Transition> | null,
didIncludeRenderPhaseUpdate: boolean,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
exitStatus: RootExitStatus,
suspendedCommitReason: SuspendedCommitReason,
completedRenderStartTime: number,
completedRenderEndTime: number,
): void {
root.cancelPendingCommit = null;
do {
flushPendingEffects();
} while (pendingEffectsStatus !== NO_PENDING_EFFECTS);
flushRenderPhaseStrictModeWarningsInDEV();
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.');
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
if (exitStatus === RootErrored) {
logErroredRenderPhase(
completedRenderStartTime,
completedRenderEndTime,
lanes,
);
} else if (recoverableErrors !== null) {
const hydrationFailed =
finishedWork !== null &&
finishedWork.alternate !== null &&
(finishedWork.alternate.memoizedState: RootState).isDehydrated &&
(finishedWork.flags & ForceClientRender) !== NoFlags;
logRecoveredRenderPhase(
completedRenderStartTime,
completedRenderEndTime,
lanes,
recoverableErrors,
hydrationFailed,
);
} else {
logRenderPhase(completedRenderStartTime, completedRenderEndTime, lanes);
}
}
if (enableSchedulingProfiler) {
markCommitStarted(lanes);
}
if (finishedWork === null) {
if (enableSchedulingProfiler) {
markCommitStopped();
}
if (enableGestureTransition) {
if (root.stoppingGestures !== null) {
stopCompletedGestures(root);
}
}
return;
} else {
if (__DEV__) {
if (lanes === NoLanes) {
console.error(
'finishedLanes should not be empty during a commit. This is a ' +
'bug in React.',
);
}
}
}
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.',
);
}
let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();
remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes);
if (enableGestureTransition && root.pendingGestures === null) {
remainingLanes &= ~GestureLane;
}
markRootFinished(
root,
lanes,
remainingLanes,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
);
didIncludeCommitPhaseUpdate = false;
if (root === workInProgressRoot) {
workInProgressRoot = null;
workInProgress = null;
workInProgressRootRenderLanes = NoLanes;
} else {
}
pendingFinishedWork = finishedWork;
pendingEffectsRoot = root;
pendingEffectsLanes = lanes;
pendingEffectsRemainingLanes = remainingLanes;
pendingPassiveTransitions = transitions;
pendingRecoverableErrors = recoverableErrors;
pendingDidIncludeRenderPhaseUpdate = didIncludeRenderPhaseUpdate;
if (enableProfilerTimer) {
pendingEffectsRenderEndTime = completedRenderEndTime;
pendingSuspendedCommitReason = suspendedCommitReason;
}
if (enableGestureTransition && isGestureRender(lanes)) {
commitGestureOnRoot(
root,
finishedWork,
recoverableErrors,
enableProfilerTimer
? suspendedCommitReason === IMMEDIATE_COMMIT
? completedRenderEndTime
: commitStartTime
: 0,
);
return;
}
let passiveSubtreeMask;
if (enableViewTransition) {
pendingViewTransitionEvents = null;
if (includesOnlyViewTransitionEligibleLanes(lanes)) {
pendingTransitionTypes = claimQueuedTransitionTypes(root);
passiveSubtreeMask = PassiveTransitionMask;
} else {
pendingTransitionTypes = null;
passiveSubtreeMask = PassiveMask;
}
} else {
passiveSubtreeMask = PassiveMask;
}
if (
(enableProfilerTimer &&
enableComponentPerformanceTrack &&
finishedWork.actualDuration !== 0) ||
(finishedWork.subtreeFlags & passiveSubtreeMask) !== NoFlags ||
(finishedWork.flags & passiveSubtreeMask) !== NoFlags
) {
if (enableYieldingBeforePassive) {
} else {
root.callbackNode = null;
root.callbackPriority = NoLane;
scheduleCallback(NormalSchedulerPriority, () => {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
trackSchedulerEvent();
}
flushPassiveEffects(true);
return null;
});
}
} else {
root.callbackNode = null;
root.callbackPriority = NoLane;
}
if (enableProfilerTimer) {
resetCommitErrors();
recordCommitTime();
if (enableComponentPerformanceTrack) {
if (suspendedCommitReason === SUSPENDED_COMMIT) {
logSuspendedCommitPhase(completedRenderEndTime, commitStartTime);
} else if (suspendedCommitReason === THROTTLED_COMMIT) {
logSuspenseThrottlePhase(completedRenderEndTime, commitStartTime);
}
}
}
resetShouldStartViewTransition();
const subtreeHasBeforeMutationEffects =
(finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask)) !==
NoFlags;
const rootHasBeforeMutationEffect =
(finishedWork.flags & (BeforeMutationMask | MutationMask)) !== NoFlags;
if (subtreeHasBeforeMutationEffects || rootHasBeforeMutationEffect) {
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
try {
commitBeforeMutationEffects(root, finishedWork, lanes);
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
}
let willStartViewTransition = shouldStartViewTransition;
if (enableGestureTransition) {
if (root.stoppingGestures !== null) {
stopCompletedGestures(root);
willStartViewTransition = false;
}
}
pendingEffectsStatus = PENDING_MUTATION_PHASE;
if (enableViewTransition && willStartViewTransition) {
pendingViewTransition = startViewTransition(
root.containerInfo,
pendingTransitionTypes,
flushMutationEffects,
flushLayoutEffects,
flushAfterMutationEffects,
flushSpawnedWork,
flushPassiveEffects,
reportViewTransitionError,
);
} else {
flushMutationEffects();
flushLayoutEffects();
flushSpawnedWork();
}
}
function reportViewTransitionError(error: mixed) {
if (pendingEffectsStatus === NO_PENDING_EFFECTS) {
return;
}
const root = pendingEffectsRoot;
const onRecoverableError = root.onRecoverableError;
onRecoverableError(error, makeErrorInfo(null));
}
function flushAfterMutationEffects(): void {
if (pendingEffectsStatus !== PENDING_AFTER_MUTATION_PHASE) {
return;
}
pendingEffectsStatus = NO_PENDING_EFFECTS;
const root = pendingEffectsRoot;
const finishedWork = pendingFinishedWork;
const lanes = pendingEffectsLanes;
commitAfterMutationEffects(root, finishedWork, lanes);
pendingEffectsStatus = PENDING_SPAWNED_WORK;
}
function flushMutationEffects(): void {
if (pendingEffectsStatus !== PENDING_MUTATION_PHASE) {
return;
}
pendingEffectsStatus = NO_PENDING_EFFECTS;
const root = pendingEffectsRoot;
const finishedWork = pendingFinishedWork;
const lanes = pendingEffectsLanes;
const subtreeMutationHasEffects =
(finishedWork.subtreeFlags & MutationMask) !== NoFlags;
const rootMutationHasEffect = (finishedWork.flags & MutationMask) !== NoFlags;
if (subtreeMutationHasEffects || rootMutationHasEffect) {
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
try {
commitMutationEffects(root, finishedWork, lanes);
if (enableCreateEventHandleAPI) {
if (shouldFireAfterActiveInstanceBlur) {
afterActiveInstanceBlur();
}
}
resetAfterCommit(root.containerInfo);
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
}
root.current = finishedWork;
pendingEffectsStatus = PENDING_LAYOUT_PHASE;
}
function flushLayoutEffects(): void {
if (pendingEffectsStatus !== PENDING_LAYOUT_PHASE) {
return;
}
pendingEffectsStatus = NO_PENDING_EFFECTS;
const root = pendingEffectsRoot;
const finishedWork = pendingFinishedWork;
const lanes = pendingEffectsLanes;
if (enableDefaultTransitionIndicator) {
const cleanUpIndicator = root.pendingIndicator;
if (cleanUpIndicator !== null && root.indicatorLanes === NoLanes) {
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
root.pendingIndicator = null;
try {
cleanUpIndicator();
} catch (x) {
reportGlobalError(x);
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
}
}
const subtreeHasLayoutEffects =
(finishedWork.subtreeFlags & LayoutMask) !== NoFlags;
const rootHasLayoutEffect = (finishedWork.flags & LayoutMask) !== NoFlags;
if (subtreeHasLayoutEffects || rootHasLayoutEffect) {
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
try {
if (enableSchedulingProfiler) {
markLayoutEffectsStarted(lanes);
}
commitLayoutEffects(finishedWork, root, lanes);
if (enableSchedulingProfiler) {
markLayoutEffectsStopped();
}
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
}
pendingEffectsStatus = PENDING_AFTER_MUTATION_PHASE;
}
function flushSpawnedWork(): void {
if (
pendingEffectsStatus !== PENDING_SPAWNED_WORK &&
pendingEffectsStatus !== PENDING_AFTER_MUTATION_PHASE
) {
return;
}
pendingEffectsStatus = NO_PENDING_EFFECTS;
pendingViewTransition = null;
requestPaint();
const root = pendingEffectsRoot;
const finishedWork = pendingFinishedWork;
const lanes = pendingEffectsLanes;
const completedRenderEndTime = pendingEffectsRenderEndTime;
const recoverableErrors = pendingRecoverableErrors;
const didIncludeRenderPhaseUpdate = pendingDidIncludeRenderPhaseUpdate;
const suspendedCommitReason = pendingSuspendedCommitReason;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
recordCommitEndTime();
logCommitPhase(
suspendedCommitReason === IMMEDIATE_COMMIT
? completedRenderEndTime
: commitStartTime,
commitEndTime,
commitErrors,
);
}
const passiveSubtreeMask =
enableViewTransition && includesOnlyViewTransitionEligibleLanes(lanes)
? PassiveTransitionMask
: PassiveMask;
const rootDidHavePassiveEffects =
(enableProfilerTimer &&
enableComponentPerformanceTrack &&
finishedWork.actualDuration !== 0) ||
(finishedWork.subtreeFlags & passiveSubtreeMask) !== NoFlags ||
(finishedWork.flags & passiveSubtreeMask) !== NoFlags;
if (rootDidHavePassiveEffects) {
pendingEffectsStatus = PENDING_PASSIVE_PHASE;
} else {
pendingEffectsStatus = NO_PENDING_EFFECTS;
pendingEffectsRoot = (null: any);
pendingFinishedWork = (null: any);
releaseRootPooledCache(root, root.pendingLanes);
if (__DEV__) {
nestedPassiveUpdateCount = 0;
rootWithPassiveNestedUpdates = null;
}
}
let remainingLanes = root.pendingLanes;
if (remainingLanes === NoLanes) {
legacyErrorBoundariesThatAlreadyFailed = null;
}
if (__DEV__) {
if (!rootDidHavePassiveEffects) {
commitDoubleInvokeEffectsInDEV(root, false);
}
}
const renderPriority = lanesToEventPriority(lanes);
onCommitRootDevTools(finishedWork.stateNode, renderPriority);
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
root.memoizedUpdaters.clear();
}
}
if (__DEV__) {
onCommitRootTestSelector();
}
if (recoverableErrors !== null) {
const prevTransition = ReactSharedInternals.T;
const previousUpdateLanePriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
ReactSharedInternals.T = null;
try {
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);
}
}
} finally {
ReactSharedInternals.T = prevTransition;
setCurrentUpdatePriority(previousUpdateLanePriority);
}
}
if (enableViewTransition) {
const pendingEvents = pendingViewTransitionEvents;
let pendingTypes = pendingTransitionTypes;
pendingTransitionTypes = null;
if (pendingEvents !== null) {
pendingViewTransitionEvents = null;
if (pendingTypes === null) {
pendingTypes = [];
}
for (let i = 0; i < pendingEvents.length; i++) {
const viewTransitionEvent = pendingEvents[i];
viewTransitionEvent(pendingTypes);
}
}
}
if (
includesSyncLane(pendingEffectsLanes) &&
(disableLegacyMode || root.tag !== LegacyRoot)
) {
flushPendingEffects();
}
ensureRootIsScheduled(root);
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, commitEndTime);
}
}
if (supportsHydration) {
flushHydrationEvents();
}
flushSyncWorkOnAllRoots();
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;
}
});
}
}
}
function commitGestureOnRoot(
root: FiberRoot,
finishedWork: Fiber,
recoverableErrors: null | Array<CapturedValue<mixed>>,
renderEndTime: number,
): void {
const finishedGesture = root.pendingGestures;
if (finishedGesture === null) {
ensureRootIsScheduled(root);
return;
}
deleteScheduledGesture(root, finishedGesture);
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
try {
insertDestinationClones(root, finishedWork);
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
pendingTransitionTypes = finishedGesture.types;
pendingEffectsStatus = PENDING_GESTURE_MUTATION_PHASE;
pendingViewTransition = finishedGesture.running = startGestureTransition(
root.containerInfo,
finishedGesture.provider,
finishedGesture.rangeStart,
finishedGesture.rangeEnd,
pendingTransitionTypes,
flushGestureMutations,
flushGestureAnimations,
reportViewTransitionError,
);
}
function flushGestureMutations(): void {
if (!enableGestureTransition) {
return;
}
if (pendingEffectsStatus !== PENDING_GESTURE_MUTATION_PHASE) {
return;
}
pendingEffectsStatus = NO_PENDING_EFFECTS;
const root = pendingEffectsRoot;
const finishedWork = pendingFinishedWork;
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
try {
applyDepartureTransitions(root, finishedWork);
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
pendingEffectsStatus = PENDING_GESTURE_ANIMATION_PHASE;
}
function flushGestureAnimations(): void {
if (!enableGestureTransition) {
return;
}
flushGestureMutations();
if (pendingEffectsStatus !== PENDING_GESTURE_ANIMATION_PHASE) {
return;
}
pendingEffectsStatus = NO_PENDING_EFFECTS;
const root = pendingEffectsRoot;
const finishedWork = pendingFinishedWork;
pendingEffectsRoot = (null: any);
pendingFinishedWork = (null: any);
pendingEffectsLanes = NoLanes;
pendingViewTransition = null;
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
try {
startGestureAnimations(root, finishedWork);
} finally {
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
}
ensureRootIsScheduled(root);
}
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) {
const pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes);
if (pooledCacheLanes === NoLanes) {
const pooledCache = root.pooledCache;
if (pooledCache != null) {
root.pooledCache = null;
releaseCache(pooledCache);
}
}
}
let didWarnAboutInterruptedViewTransitions = false;
export function flushPendingEffects(wasDelayedCommit?: boolean): boolean {
if (enableViewTransition && pendingViewTransition !== null) {
stopViewTransition(pendingViewTransition);
if (__DEV__) {
if (!didWarnAboutInterruptedViewTransitions) {
didWarnAboutInterruptedViewTransitions = true;
console.warn(
'A flushSync update cancelled a View Transition because it was called ' +
'while the View Transition was still preparing. To preserve the synchronous ' +
'semantics, React had to skip the View Transition. If you can, try to avoid ' +
"flushSync() in a scenario that's likely to interfere.",
);
}
}
pendingViewTransition = null;
}
flushGestureMutations();
flushGestureAnimations();
flushMutationEffects();
flushLayoutEffects();
flushSpawnedWork();
return flushPassiveEffects(wasDelayedCommit);
}
function flushPassiveEffects(wasDelayedCommit?: boolean): boolean {
if (pendingEffectsStatus !== PENDING_PASSIVE_PHASE) {
return false;
}
const root = pendingEffectsRoot;
const remainingLanes = pendingEffectsRemainingLanes;
pendingEffectsRemainingLanes = NoLanes;
const renderPriority = lanesToEventPriority(pendingEffectsLanes);
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);
}
}
function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) {
const transitions = pendingPassiveTransitions;
pendingPassiveTransitions = null;
const root = pendingEffectsRoot;
const lanes = pendingEffectsLanes;
pendingEffectsStatus = NO_PENDING_EFFECTS;
pendingEffectsRoot = (null: any);
pendingFinishedWork = (null: any);
pendingEffectsLanes = NoLanes;
if (enableYieldingBeforePassive) {
root.callbackNode = null;
root.callbackPriority = NoLane;
}
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;
}
let passiveEffectStartTime = 0;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
resetCommitErrors();
passiveEffectStartTime = now();
logPaintYieldPhase(
commitEndTime,
passiveEffectStartTime,
!!wasDelayedCommit,
);
}
if (enableSchedulingProfiler) {
markPassiveEffectsStarted(lanes);
}
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
commitPassiveUnmountEffects(root.current);
commitPassiveMountEffects(
root,
root.current,
lanes,
transitions,
pendingEffectsRenderEndTime,
);
if (enableSchedulingProfiler) {
markPassiveEffectsStopped();
}
if (__DEV__) {
commitDoubleInvokeEffectsInDEV(root, true);
}
executionContext = prevExecutionContext;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
const passiveEffectsEndTime = now();
logPassiveCommitPhase(
passiveEffectStartTime,
passiveEffectsEndTime,
commitErrors,
);
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;
}
if (enableYieldingBeforePassive) {
ensureRootIsScheduled(root);
}
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);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
recordEffectError(errorInfo);
}
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);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
recordEffectError(errorInfo);
}
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);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
startPingTimerByLanes(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 ActivityComponent:
case SuspenseComponent:
retryCache = boundaryFiber.stateNode;
const suspenseState: null | SuspenseState | ActivityState =
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) {
setIsStrictModeForDevtools(true);
try {
disappearLayoutEffects(fiber);
disconnectPassiveEffect(fiber);
reappearLayoutEffects(root, fiber.alternate, fiber, false);
reconnectPassiveEffects(root, fiber, NoLanes, null, false, 0);
} finally {
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);
}
} 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 (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 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;
}
}