import type {
MutableSource,
MutableSourceGetSnapshotFn,
MutableSourceSubscribeFn,
ReactContext,
StartTransitionOptions,
Usable,
Thenable,
} from 'shared/ReactTypes';
import type {
Fiber,
FiberRoot,
Dispatcher,
HookType,
MemoCache,
} from './ReactInternalTypes';
import type {Lanes, Lane} from './ReactFiberLane';
import type {HookFlags} from './ReactHookEffectTags';
import type {Flags} from './ReactFiberFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import {
enableDebugTracing,
enableSchedulingProfiler,
enableCache,
enableUseRefAccessWarning,
enableLazyContextPropagation,
enableUseMutableSource,
enableTransitionTracing,
enableUseHook,
enableUseMemoCacheHook,
enableUseEffectEventHook,
enableLegacyCache,
debugRenderPhaseSideEffectsForStrictMode,
} from 'shared/ReactFeatureFlags';
import {
REACT_CONTEXT_TYPE,
REACT_SERVER_CONTEXT_TYPE,
REACT_MEMO_CACHE_SENTINEL,
} from 'shared/ReactSymbols';
import {
NoMode,
ConcurrentMode,
DebugTracingMode,
StrictEffectsMode,
StrictLegacyMode,
} from './ReactTypeOfMode';
import {
NoLane,
SyncLane,
OffscreenLane,
NoLanes,
isSubsetOfLanes,
includesBlockingLane,
includesOnlyNonUrgentLanes,
claimNextTransitionLane,
mergeLanes,
removeLanes,
intersectLanes,
isTransitionLane,
markRootEntangled,
markRootMutableRead,
NoTimestamp,
} from './ReactFiberLane';
import {
ContinuousEventPriority,
getCurrentUpdatePriority,
setCurrentUpdatePriority,
higherEventPriority,
} from './ReactEventPriorities';
import {readContext, checkIfContextChanged} from './ReactFiberNewContext';
import {HostRoot, CacheComponent} from './ReactWorkTags';
import {
LayoutStatic as LayoutStaticEffect,
Passive as PassiveEffect,
PassiveStatic as PassiveStaticEffect,
StaticMask as StaticMaskEffect,
Update as UpdateEffect,
StoreConsistency,
MountLayoutDev as MountLayoutDevEffect,
MountPassiveDev as MountPassiveDevEffect,
} from './ReactFiberFlags';
import {
HasEffect as HookHasEffect,
Layout as HookLayout,
Passive as HookPassive,
Insertion as HookInsertion,
} from './ReactHookEffectTags';
import {
getWorkInProgressRoot,
getWorkInProgressRootRenderLanes,
scheduleUpdateOnFiber,
requestUpdateLane,
requestEventTime,
markSkippedUpdateLanes,
isInvalidExecutionContextForEventFunction,
} from './ReactFiberWorkLoop';
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
import is from 'shared/objectIs';
import isArray from 'shared/isArray';
import {
markWorkInProgressReceivedUpdate,
checkIfWorkInProgressReceivedUpdate,
} from './ReactFiberBeginWork';
import {getIsHydrating} from './ReactFiberHydrationContext';
import {
getWorkInProgressVersion,
markSourceAsDirty,
setWorkInProgressVersion,
warnAboutMultipleRenderersDEV,
} from './ReactMutableSource';
import {logStateUpdateScheduled} from './DebugTracing';
import {
markStateUpdateScheduled,
setIsStrictModeForDevtools,
} from './ReactFiberDevToolsHook';
import {createCache} from './ReactFiberCacheComponent';
import {
createUpdate as createLegacyQueueUpdate,
enqueueUpdate as enqueueLegacyQueueUpdate,
entangleTransitions as entangleLegacyQueueTransitions,
} from './ReactFiberClassUpdateQueue';
import {
enqueueConcurrentHookUpdate,
enqueueConcurrentHookUpdateAndEagerlyBailout,
enqueueConcurrentRenderForLane,
} from './ReactFiberConcurrentUpdates';
import {getTreeId} from './ReactFiberTreeContext';
import {now} from './Scheduler';
import {
trackUsedThenable,
checkIfUseWrappedInTryCatch,
createThenableState,
} from './ReactFiberThenable';
import type {ThenableState} from './ReactFiberThenable';
import type {BatchConfigTransition} from './ReactFiberTracingMarkerComponent';
const {ReactCurrentDispatcher, ReactCurrentBatchConfig} = ReactSharedInternals;
export type Update<S, A> = {
lane: Lane,
action: A,
hasEagerState: boolean,
eagerState: S | null,
next: Update<S, A>,
};
export type UpdateQueue<S, A> = {
pending: Update<S, A> | null,
lanes: Lanes,
dispatch: (A => mixed) | null,
lastRenderedReducer: ((S, A) => S) | null,
lastRenderedState: S | null,
};
let didWarnAboutMismatchedHooksForComponent;
let didWarnUncachedGetSnapshot: void | true;
let didWarnAboutUseWrappedInTryCatch;
if (__DEV__) {
didWarnAboutMismatchedHooksForComponent = new Set<string | null>();
didWarnAboutUseWrappedInTryCatch = new Set<string | null>();
}
export type Hook = {
memoizedState: any,
baseState: any,
baseQueue: Update<any, any> | null,
queue: any,
next: Hook | null,
};
export type Effect = {
tag: HookFlags,
create: () => (() => void) | void,
destroy: (() => void) | void,
deps: Array<mixed> | void | null,
next: Effect,
};
type StoreInstance<T> = {
value: T,
getSnapshot: () => T,
};
type StoreConsistencyCheck<T> = {
value: T,
getSnapshot: () => T,
};
type EventFunctionPayload<Args, Return, F: (...Array<Args>) => Return> = {
ref: {
eventFn: F,
impl: F,
},
nextImpl: F,
};
export type FunctionComponentUpdateQueue = {
lastEffect: Effect | null,
events: Array<EventFunctionPayload<any, any, any>> | null,
stores: Array<StoreConsistencyCheck<any>> | null,
memoCache?: MemoCache | null,
};
type BasicStateAction<S> = (S => S) | S;
type Dispatch<A> = A => void;
let renderLanes: Lanes = NoLanes;
let currentlyRenderingFiber: Fiber = (null: any);
let currentHook: Hook | null = null;
let workInProgressHook: Hook | null = null;
let didScheduleRenderPhaseUpdate: boolean = false;
let didScheduleRenderPhaseUpdateDuringThisPass: boolean = false;
let shouldDoubleInvokeUserFnsInHooksDEV: boolean = false;
let localIdCounter: number = 0;
let thenableIndexCounter: number = 0;
let thenableState: ThenableState | null = null;
let globalClientIdCounter: number = 0;
const RE_RENDER_LIMIT = 25;
let currentHookNameInDev: ?HookType = null;
let hookTypesDev: Array<HookType> | null = null;
let hookTypesUpdateIndexDev: number = -1;
let ignorePreviousDependencies: boolean = false;
function mountHookTypesDev(): void {
if (__DEV__) {
const hookName = ((currentHookNameInDev: any): HookType);
if (hookTypesDev === null) {
hookTypesDev = [hookName];
} else {
hookTypesDev.push(hookName);
}
}
}
function updateHookTypesDev(): void {
if (__DEV__) {
const hookName = ((currentHookNameInDev: any): HookType);
if (hookTypesDev !== null) {
hookTypesUpdateIndexDev++;
if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) {
warnOnHookMismatchInDev(hookName);
}
}
}
}
function checkDepsAreArrayDev(deps: mixed): void {
if (__DEV__) {
if (deps !== undefined && deps !== null && !isArray(deps)) {
console.error(
'%s received a final argument that is not an array (instead, received `%s`). When ' +
'specified, the final argument must be an array.',
currentHookNameInDev,
typeof deps,
);
}
}
}
function warnOnHookMismatchInDev(currentHookName: HookType): void {
if (__DEV__) {
const componentName = getComponentNameFromFiber(currentlyRenderingFiber);
if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) {
didWarnAboutMismatchedHooksForComponent.add(componentName);
if (hookTypesDev !== null) {
let table = '';
const secondColumnStart = 30;
for (let i = 0; i <= ((hookTypesUpdateIndexDev: any): number); i++) {
const oldHookName = hookTypesDev[i];
const newHookName =
i === ((hookTypesUpdateIndexDev: any): number)
? currentHookName
: oldHookName;
let row = `${i + 1}. ${oldHookName}`;
while (row.length < secondColumnStart) {
row += ' ';
}
row += newHookName + '\n';
table += row;
}
console.error(
'React has detected a change in the order of Hooks called by %s. ' +
'This will lead to bugs and errors if not fixed. ' +
'For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks\n\n' +
' Previous render Next render\n' +
' ------------------------------------------------------\n' +
'%s' +
' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n',
componentName,
table,
);
}
}
}
}
function throwInvalidHookError() {
throw new Error(
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
' one of the following reasons:\n' +
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
'2. You might be breaking the Rules of Hooks\n' +
'3. You might have more than one copy of React in the same app\n' +
'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
);
}
function areHookInputsEqual(
nextDeps: Array<mixed>,
prevDeps: Array<mixed> | null,
): boolean {
if (__DEV__) {
if (ignorePreviousDependencies) {
return false;
}
}
if (prevDeps === null) {
if (__DEV__) {
console.error(
'%s received a final argument during this render, but not during ' +
'the previous render. Even though the final argument is optional, ' +
'its type cannot change between renders.',
currentHookNameInDev,
);
}
return false;
}
if (__DEV__) {
if (nextDeps.length !== prevDeps.length) {
console.error(
'The final argument passed to %s changed size between renders. The ' +
'order and size of this array must remain constant.\n\n' +
'Previous: %s\n' +
'Incoming: %s',
currentHookNameInDev,
`[${prevDeps.join(', ')}]`,
`[${nextDeps.join(', ')}]`,
);
}
}
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
}
export function renderWithHooks<Props, SecondArg>(
current: Fiber | null,
workInProgress: Fiber,
Component: (p: Props, arg: SecondArg) => any,
props: Props,
secondArg: SecondArg,
nextRenderLanes: Lanes,
): any {
renderLanes = nextRenderLanes;
currentlyRenderingFiber = workInProgress;
if (__DEV__) {
hookTypesDev =
current !== null
? ((current._debugHookTypes: any): Array<HookType>)
: null;
hookTypesUpdateIndexDev = -1;
ignorePreviousDependencies =
current !== null && current.type !== workInProgress.type;
}
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
workInProgress.lanes = NoLanes;
if (__DEV__) {
if (current !== null && current.memoizedState !== null) {
ReactCurrentDispatcher.current = HooksDispatcherOnUpdateInDEV;
} else if (hookTypesDev !== null) {
ReactCurrentDispatcher.current = HooksDispatcherOnMountWithHookTypesInDEV;
} else {
ReactCurrentDispatcher.current = HooksDispatcherOnMountInDEV;
}
} else {
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
}
const shouldDoubleRenderDEV =
__DEV__ &&
debugRenderPhaseSideEffectsForStrictMode &&
(workInProgress.mode & StrictLegacyMode) !== NoMode;
shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV;
let children = Component(props, secondArg);
shouldDoubleInvokeUserFnsInHooksDEV = false;
if (didScheduleRenderPhaseUpdateDuringThisPass) {
children = renderWithHooksAgain(
workInProgress,
Component,
props,
secondArg,
);
}
if (shouldDoubleRenderDEV) {
setIsStrictModeForDevtools(true);
try {
children = renderWithHooksAgain(
workInProgress,
Component,
props,
secondArg,
);
} finally {
setIsStrictModeForDevtools(false);
}
}
finishRenderingHooks(current, workInProgress);
return children;
}
function finishRenderingHooks(current: Fiber | null, workInProgress: Fiber) {
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
if (__DEV__) {
workInProgress._debugHookTypes = hookTypesDev;
}
const didRenderTooFewHooks =
currentHook !== null && currentHook.next !== null;
renderLanes = NoLanes;
currentlyRenderingFiber = (null: any);
currentHook = null;
workInProgressHook = null;
if (__DEV__) {
currentHookNameInDev = null;
hookTypesDev = null;
hookTypesUpdateIndexDev = -1;
if (
current !== null &&
(current.flags & StaticMaskEffect) !==
(workInProgress.flags & StaticMaskEffect) &&
(current.mode & ConcurrentMode) !== NoMode
) {
console.error(
'Internal React error: Expected static flag was missing. Please ' +
'notify the React team.',
);
}
}
didScheduleRenderPhaseUpdate = false;
thenableIndexCounter = 0;
thenableState = null;
if (didRenderTooFewHooks) {
throw new Error(
'Rendered fewer hooks than expected. This may be caused by an accidental ' +
'early return statement.',
);
}
if (enableLazyContextPropagation) {
if (current !== null) {
if (!checkIfWorkInProgressReceivedUpdate()) {
const currentDependencies = current.dependencies;
if (
currentDependencies !== null &&
checkIfContextChanged(currentDependencies)
) {
markWorkInProgressReceivedUpdate();
}
}
}
}
if (__DEV__) {
if (checkIfUseWrappedInTryCatch()) {
const componentName =
getComponentNameFromFiber(workInProgress) || 'Unknown';
if (!didWarnAboutUseWrappedInTryCatch.has(componentName)) {
didWarnAboutUseWrappedInTryCatch.add(componentName);
console.error(
'`use` was called from inside a try/catch block. This is not allowed ' +
'and can lead to unexpected behavior. To handle errors triggered ' +
'by `use`, wrap your component in a error boundary.',
);
}
}
}
}
export function replaySuspendedComponentWithHooks<Props, SecondArg>(
current: Fiber | null,
workInProgress: Fiber,
Component: (p: Props, arg: SecondArg) => any,
props: Props,
secondArg: SecondArg,
): any {
if (__DEV__) {
hookTypesUpdateIndexDev = -1;
ignorePreviousDependencies =
current !== null && current.type !== workInProgress.type;
}
const children = renderWithHooksAgain(
workInProgress,
Component,
props,
secondArg,
);
finishRenderingHooks(current, workInProgress);
return children;
}
function renderWithHooksAgain<Props, SecondArg>(
workInProgress: Fiber,
Component: (p: Props, arg: SecondArg) => any,
props: Props,
secondArg: SecondArg,
): any {
let numberOfReRenders: number = 0;
let children;
do {
if (didScheduleRenderPhaseUpdateDuringThisPass) {
thenableState = null;
}
thenableIndexCounter = 0;
didScheduleRenderPhaseUpdateDuringThisPass = false;
if (numberOfReRenders >= RE_RENDER_LIMIT) {
throw new Error(
'Too many re-renders. React limits the number of renders to prevent ' +
'an infinite loop.',
);
}
numberOfReRenders += 1;
if (__DEV__) {
ignorePreviousDependencies = false;
}
currentHook = null;
workInProgressHook = null;
workInProgress.updateQueue = null;
if (__DEV__) {
hookTypesUpdateIndexDev = -1;
}
ReactCurrentDispatcher.current = __DEV__
? HooksDispatcherOnRerenderInDEV
: HooksDispatcherOnRerender;
children = Component(props, secondArg);
} while (didScheduleRenderPhaseUpdateDuringThisPass);
return children;
}
export function checkDidRenderIdHook(): boolean {
const didRenderIdHook = localIdCounter !== 0;
localIdCounter = 0;
return didRenderIdHook;
}
export function bailoutHooks(
current: Fiber,
workInProgress: Fiber,
lanes: Lanes,
): void {
workInProgress.updateQueue = current.updateQueue;
if (__DEV__ && (workInProgress.mode & StrictEffectsMode) !== NoMode) {
workInProgress.flags &= ~(
MountPassiveDevEffect |
MountLayoutDevEffect |
PassiveEffect |
UpdateEffect
);
} else {
workInProgress.flags &= ~(PassiveEffect | UpdateEffect);
}
current.lanes = removeLanes(current.lanes, lanes);
}
export function resetHooksAfterThrow(): void {
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
}
export function resetHooksOnUnwind(): void {
if (didScheduleRenderPhaseUpdate) {
let hook: Hook | null = currentlyRenderingFiber.memoizedState;
while (hook !== null) {
const queue = hook.queue;
if (queue !== null) {
queue.pending = null;
}
hook = hook.next;
}
didScheduleRenderPhaseUpdate = false;
}
renderLanes = NoLanes;
currentlyRenderingFiber = (null: any);
currentHook = null;
workInProgressHook = null;
if (__DEV__) {
hookTypesDev = null;
hookTypesUpdateIndexDev = -1;
currentHookNameInDev = null;
}
didScheduleRenderPhaseUpdateDuringThisPass = false;
localIdCounter = 0;
thenableIndexCounter = 0;
thenableState = null;
}
function mountWorkInProgressHook(): Hook {
const hook: Hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null,
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
function updateWorkInProgressHook(): Hook {
let nextCurrentHook: null | Hook;
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate;
if (current !== null) {
nextCurrentHook = current.memoizedState;
} else {
nextCurrentHook = null;
}
} else {
nextCurrentHook = currentHook.next;
}
let nextWorkInProgressHook: null | Hook;
if (workInProgressHook === null) {
nextWorkInProgressHook = currentlyRenderingFiber.memoizedState;
} else {
nextWorkInProgressHook = workInProgressHook.next;
}
if (nextWorkInProgressHook !== null) {
workInProgressHook = nextWorkInProgressHook;
nextWorkInProgressHook = workInProgressHook.next;
currentHook = nextCurrentHook;
} else {
if (nextCurrentHook === null) {
const currentFiber = currentlyRenderingFiber.alternate;
if (currentFiber === null) {
throw new Error(
'Update hook called on initial render. This is likely a bug in React. Please file an issue.',
);
} else {
throw new Error('Rendered more hooks than during the previous render.');
}
}
currentHook = nextCurrentHook;
const newHook: Hook = {
memoizedState: currentHook.memoizedState,
baseState: currentHook.baseState,
baseQueue: currentHook.baseQueue,
queue: currentHook.queue,
next: null,
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook;
} else {
workInProgressHook = workInProgressHook.next = newHook;
}
}
return workInProgressHook;
}
let createFunctionComponentUpdateQueue: () => FunctionComponentUpdateQueue;
if (enableUseMemoCacheHook) {
createFunctionComponentUpdateQueue = () => {
return {
lastEffect: null,
events: null,
stores: null,
memoCache: null,
};
};
} else {
createFunctionComponentUpdateQueue = () => {
return {
lastEffect: null,
events: null,
stores: null,
};
};
}
function use<T>(usable: Usable<T>): T {
if (usable !== null && typeof usable === 'object') {
if (typeof usable.then === 'function') {
const thenable: Thenable<T> = (usable: any);
const index = thenableIndexCounter;
thenableIndexCounter += 1;
if (thenableState === null) {
thenableState = createThenableState();
}
const result = trackUsedThenable(thenableState, thenable, index);
if (
currentlyRenderingFiber.alternate === null &&
(workInProgressHook === null
? currentlyRenderingFiber.memoizedState === null
: workInProgressHook.next === null)
) {
if (__DEV__) {
ReactCurrentDispatcher.current = HooksDispatcherOnMountInDEV;
} else {
ReactCurrentDispatcher.current = HooksDispatcherOnMount;
}
}
return result;
} else if (
usable.$$typeof === REACT_CONTEXT_TYPE ||
usable.$$typeof === REACT_SERVER_CONTEXT_TYPE
) {
const context: ReactContext<T> = (usable: any);
return readContext(context);
}
}
throw new Error('An unsupported type was passed to use(): ' + String(usable));
}
function useMemoCache(size: number): Array<any> {
let memoCache = null;
let updateQueue: FunctionComponentUpdateQueue | null =
(currentlyRenderingFiber.updateQueue: any);
if (updateQueue !== null) {
memoCache = updateQueue.memoCache;
}
if (memoCache == null) {
const current: Fiber | null = currentlyRenderingFiber.alternate;
if (current !== null) {
const currentUpdateQueue: FunctionComponentUpdateQueue | null =
(current.updateQueue: any);
if (currentUpdateQueue !== null) {
const currentMemoCache: ?MemoCache = currentUpdateQueue.memoCache;
if (currentMemoCache != null) {
memoCache = {
data: currentMemoCache.data.map(array => array.slice()),
index: 0,
};
}
}
}
}
if (memoCache == null) {
memoCache = {
data: [],
index: 0,
};
}
if (updateQueue === null) {
updateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = updateQueue;
}
updateQueue.memoCache = memoCache;
let data = memoCache.data[memoCache.index];
if (data === undefined) {
data = memoCache.data[memoCache.index] = new Array(size);
for (let i = 0; i < size; i++) {
data[i] = REACT_MEMO_CACHE_SENTINEL;
}
} else if (data.length !== size) {
if (__DEV__) {
console.error(
'Expected a constant size argument for each invocation of useMemoCache. ' +
'The previous cache was allocated with size %s but size %s was requested.',
data.length,
size,
);
}
}
memoCache.index++;
return data;
}
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
return typeof action === 'function' ? action(state) : action;
}
function mountReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const hook = mountWorkInProgressHook();
let initialState;
if (init !== undefined) {
initialState = init(initialArg);
} else {
initialState = ((initialArg: any): S);
}
hook.memoizedState = hook.baseState = initialState;
const queue: UpdateQueue<S, A> = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: reducer,
lastRenderedState: (initialState: any),
};
hook.queue = queue;
const dispatch: Dispatch<A> = (queue.dispatch = (dispatchReducerAction.bind(
null,
currentlyRenderingFiber,
queue,
): any));
return [hook.memoizedState, dispatch];
}
function updateReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
if (queue === null) {
throw new Error(
'Should have a queue. This is likely a bug in React. Please file an issue.',
);
}
queue.lastRenderedReducer = reducer;
const current: Hook = (currentHook: any);
let baseQueue = current.baseQueue;
const pendingQueue = queue.pending;
if (pendingQueue !== null) {
if (baseQueue !== null) {
const baseFirst = baseQueue.next;
const pendingFirst = pendingQueue.next;
baseQueue.next = pendingFirst;
pendingQueue.next = baseFirst;
}
if (__DEV__) {
if (current.baseQueue !== baseQueue) {
console.error(
'Internal error: Expected work-in-progress queue to be a clone. ' +
'This is a bug in React.',
);
}
}
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (baseQueue !== null) {
const first = baseQueue.next;
let newState = current.baseState;
let newBaseState = null;
let newBaseQueueFirst = null;
let newBaseQueueLast: Update<S, A> | null = null;
let update = first;
do {
const updateLane = removeLanes(update.lane, OffscreenLane);
const isHiddenUpdate = updateLane !== update.lane;
const shouldSkipUpdate = isHiddenUpdate
? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane)
: !isSubsetOfLanes(renderLanes, updateLane);
if (shouldSkipUpdate) {
const clone: Update<S, A> = {
lane: updateLane,
action: update.action,
hasEagerState: update.hasEagerState,
eagerState: update.eagerState,
next: (null: any),
};
if (newBaseQueueLast === null) {
newBaseQueueFirst = newBaseQueueLast = clone;
newBaseState = newState;
} else {
newBaseQueueLast = newBaseQueueLast.next = clone;
}
currentlyRenderingFiber.lanes = mergeLanes(
currentlyRenderingFiber.lanes,
updateLane,
);
markSkippedUpdateLanes(updateLane);
} else {
if (newBaseQueueLast !== null) {
const clone: Update<S, A> = {
lane: NoLane,
action: update.action,
hasEagerState: update.hasEagerState,
eagerState: update.eagerState,
next: (null: any),
};
newBaseQueueLast = newBaseQueueLast.next = clone;
}
const action = update.action;
if (shouldDoubleInvokeUserFnsInHooksDEV) {
reducer(newState, action);
}
if (update.hasEagerState) {
newState = ((update.eagerState: any): S);
} else {
newState = reducer(newState, action);
}
}
update = update.next;
} while (update !== null && update !== first);
if (newBaseQueueLast === null) {
newBaseState = newState;
} else {
newBaseQueueLast.next = (newBaseQueueFirst: any);
}
if (!is(newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = newState;
hook.baseState = newBaseState;
hook.baseQueue = newBaseQueueLast;
queue.lastRenderedState = newState;
}
if (baseQueue === null) {
queue.lanes = NoLanes;
}
const dispatch: Dispatch<A> = (queue.dispatch: any);
return [hook.memoizedState, dispatch];
}
function rerenderReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
if (queue === null) {
throw new Error(
'Should have a queue. This is likely a bug in React. Please file an issue.',
);
}
queue.lastRenderedReducer = reducer;
const dispatch: Dispatch<A> = (queue.dispatch: any);
const lastRenderPhaseUpdate = queue.pending;
let newState = hook.memoizedState;
if (lastRenderPhaseUpdate !== null) {
queue.pending = null;
const firstRenderPhaseUpdate = lastRenderPhaseUpdate.next;
let update = firstRenderPhaseUpdate;
do {
const action = update.action;
newState = reducer(newState, action);
update = update.next;
} while (update !== firstRenderPhaseUpdate);
if (!is(newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = newState;
if (hook.baseQueue === null) {
hook.baseState = newState;
}
queue.lastRenderedState = newState;
}
return [newState, dispatch];
}
type MutableSourceMemoizedState<Source, Snapshot> = {
refs: {
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
setSnapshot: Snapshot => void,
},
source: MutableSource<any>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
};
function readFromUnsubscribedMutableSource<Source, Snapshot>(
root: FiberRoot,
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
): Snapshot {
if (__DEV__) {
warnAboutMultipleRenderersDEV(source);
}
const getVersion = source._getVersion;
const version = getVersion(source._source);
let isSafeToReadFromSource = false;
const currentRenderVersion = getWorkInProgressVersion(source);
if (currentRenderVersion !== null) {
isSafeToReadFromSource = currentRenderVersion === version;
} else {
isSafeToReadFromSource = isSubsetOfLanes(
renderLanes,
root.mutableReadLanes,
);
if (isSafeToReadFromSource) {
setWorkInProgressVersion(source, version);
}
}
if (isSafeToReadFromSource) {
const snapshot = getSnapshot(source._source);
if (__DEV__) {
if (typeof snapshot === 'function') {
console.error(
'Mutable source should not return a function as the snapshot value. ' +
'Functions may close over mutable values and cause tearing.',
);
}
}
return snapshot;
} else {
markSourceAsDirty(source);
throw new Error(
'Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.',
);
}
}
function useMutableSource<Source, Snapshot>(
hook: Hook,
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
if (!enableUseMutableSource) {
return (undefined: any);
}
const root = ((getWorkInProgressRoot(): any): FiberRoot);
if (root === null) {
throw new Error(
'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
);
}
const getVersion = source._getVersion;
const version = getVersion(source._source);
const dispatcher = ReactCurrentDispatcher.current;
let [currentSnapshot, setSnapshot] = dispatcher.useState(() =>
readFromUnsubscribedMutableSource(root, source, getSnapshot),
);
let snapshot = currentSnapshot;
const stateHook = ((workInProgressHook: any): Hook);
const memoizedState = ((hook.memoizedState: any): MutableSourceMemoizedState<
Source,
Snapshot,
>);
const refs = memoizedState.refs;
const prevGetSnapshot = refs.getSnapshot;
const prevSource = memoizedState.source;
const prevSubscribe = memoizedState.subscribe;
const fiber = currentlyRenderingFiber;
hook.memoizedState = ({
refs,
source,
subscribe,
}: MutableSourceMemoizedState<Source, Snapshot>);
dispatcher.useEffect(() => {
refs.getSnapshot = getSnapshot;
refs.setSnapshot = setSnapshot;
const maybeNewVersion = getVersion(source._source);
if (!is(version, maybeNewVersion)) {
const maybeNewSnapshot = getSnapshot(source._source);
if (__DEV__) {
if (typeof maybeNewSnapshot === 'function') {
console.error(
'Mutable source should not return a function as the snapshot value. ' +
'Functions may close over mutable values and cause tearing.',
);
}
}
if (!is(snapshot, maybeNewSnapshot)) {
setSnapshot(maybeNewSnapshot);
const lane = requestUpdateLane(fiber);
markRootMutableRead(root, lane);
}
markRootEntangled(root, root.mutableReadLanes);
}
}, [getSnapshot, source, subscribe]);
dispatcher.useEffect(() => {
const handleChange = () => {
const latestGetSnapshot = refs.getSnapshot;
const latestSetSnapshot = refs.setSnapshot;
try {
latestSetSnapshot(latestGetSnapshot(source._source));
const lane = requestUpdateLane(fiber);
markRootMutableRead(root, lane);
} catch (error) {
latestSetSnapshot(
(() => {
throw error;
}: any),
);
}
};
const unsubscribe = subscribe(source._source, handleChange);
if (__DEV__) {
if (typeof unsubscribe !== 'function') {
console.error(
'Mutable source subscribe function must return an unsubscribe function.',
);
}
}
return unsubscribe;
}, [source, subscribe]);
if (
!is(prevGetSnapshot, getSnapshot) ||
!is(prevSource, source) ||
!is(prevSubscribe, subscribe)
) {
const newQueue: UpdateQueue<Snapshot, BasicStateAction<Snapshot>> = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: snapshot,
};
newQueue.dispatch = setSnapshot = (dispatchSetState.bind(
null,
currentlyRenderingFiber,
newQueue,
): any);
stateHook.queue = newQueue;
stateHook.baseQueue = null;
snapshot = readFromUnsubscribedMutableSource(root, source, getSnapshot);
stateHook.memoizedState = stateHook.baseState = snapshot;
}
return snapshot;
}
function mountMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
if (!enableUseMutableSource) {
return (undefined: any);
}
const hook = mountWorkInProgressHook();
hook.memoizedState = ({
refs: {
getSnapshot,
setSnapshot: (null: any),
},
source,
subscribe,
}: MutableSourceMemoizedState<Source, Snapshot>);
return useMutableSource(hook, source, getSnapshot, subscribe);
}
function updateMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
if (!enableUseMutableSource) {
return (undefined: any);
}
const hook = updateWorkInProgressHook();
return useMutableSource(hook, source, getSnapshot, subscribe);
}
function mountSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
const fiber = currentlyRenderingFiber;
const hook = mountWorkInProgressHook();
let nextSnapshot;
const isHydrating = getIsHydrating();
if (isHydrating) {
if (getServerSnapshot === undefined) {
throw new Error(
'Missing getServerSnapshot, which is required for ' +
'server-rendered content. Will revert to client rendering.',
);
}
nextSnapshot = getServerSnapshot();
if (__DEV__) {
if (!didWarnUncachedGetSnapshot) {
if (nextSnapshot !== getServerSnapshot()) {
console.error(
'The result of getServerSnapshot should be cached to avoid an infinite loop',
);
didWarnUncachedGetSnapshot = true;
}
}
}
} else {
nextSnapshot = getSnapshot();
if (__DEV__) {
if (!didWarnUncachedGetSnapshot) {
const cachedSnapshot = getSnapshot();
if (!is(nextSnapshot, cachedSnapshot)) {
console.error(
'The result of getSnapshot should be cached to avoid an infinite loop',
);
didWarnUncachedGetSnapshot = true;
}
}
}
const root: FiberRoot | null = getWorkInProgressRoot();
if (root === null) {
throw new Error(
'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
);
}
if (!includesBlockingLane(root, renderLanes)) {
pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot);
}
}
hook.memoizedState = nextSnapshot;
const inst: StoreInstance<T> = {
value: nextSnapshot,
getSnapshot,
};
hook.queue = inst;
mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]);
fiber.flags |= PassiveEffect;
pushEffect(
HookHasEffect | HookPassive,
updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot),
undefined,
null,
);
return nextSnapshot;
}
function updateSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
const fiber = currentlyRenderingFiber;
const hook = updateWorkInProgressHook();
const nextSnapshot = getSnapshot();
if (__DEV__) {
if (!didWarnUncachedGetSnapshot) {
const cachedSnapshot = getSnapshot();
if (!is(nextSnapshot, cachedSnapshot)) {
console.error(
'The result of getSnapshot should be cached to avoid an infinite loop',
);
didWarnUncachedGetSnapshot = true;
}
}
}
const prevSnapshot = (currentHook || hook).memoizedState;
const snapshotChanged = !is(prevSnapshot, nextSnapshot);
if (snapshotChanged) {
hook.memoizedState = nextSnapshot;
markWorkInProgressReceivedUpdate();
}
const inst = hook.queue;
updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [
subscribe,
]);
if (
inst.getSnapshot !== getSnapshot ||
snapshotChanged ||
(workInProgressHook !== null &&
workInProgressHook.memoizedState.tag & HookHasEffect)
) {
fiber.flags |= PassiveEffect;
pushEffect(
HookHasEffect | HookPassive,
updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot),
undefined,
null,
);
const root: FiberRoot | null = getWorkInProgressRoot();
if (root === null) {
throw new Error(
'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
);
}
if (!includesBlockingLane(root, renderLanes)) {
pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot);
}
}
return nextSnapshot;
}
function pushStoreConsistencyCheck<T>(
fiber: Fiber,
getSnapshot: () => T,
renderedSnapshot: T,
): void {
fiber.flags |= StoreConsistency;
const check: StoreConsistencyCheck<T> = {
getSnapshot,
value: renderedSnapshot,
};
let componentUpdateQueue: null | FunctionComponentUpdateQueue =
(currentlyRenderingFiber.updateQueue: any);
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = (componentUpdateQueue: any);
componentUpdateQueue.stores = [check];
} else {
const stores = componentUpdateQueue.stores;
if (stores === null) {
componentUpdateQueue.stores = [check];
} else {
stores.push(check);
}
}
}
function updateStoreInstance<T>(
fiber: Fiber,
inst: StoreInstance<T>,
nextSnapshot: T,
getSnapshot: () => T,
): void {
inst.value = nextSnapshot;
inst.getSnapshot = getSnapshot;
if (checkIfSnapshotChanged(inst)) {
forceStoreRerender(fiber);
}
}
function subscribeToStore<T>(
fiber: Fiber,
inst: StoreInstance<T>,
subscribe: (() => void) => () => void,
): any {
const handleStoreChange = () => {
if (checkIfSnapshotChanged(inst)) {
forceStoreRerender(fiber);
}
};
return subscribe(handleStoreChange);
}
function checkIfSnapshotChanged<T>(inst: StoreInstance<T>): boolean {
const latestGetSnapshot = inst.getSnapshot;
const prevValue = inst.value;
try {
const nextValue = latestGetSnapshot();
return !is(prevValue, nextValue);
} catch (error) {
return true;
}
}
function forceStoreRerender(fiber: Fiber) {
const root = enqueueConcurrentRenderForLane(fiber, SyncLane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
}
}
function mountState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
const queue: UpdateQueue<S, BasicStateAction<S>> = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any),
};
hook.queue = queue;
const dispatch: Dispatch<BasicStateAction<S>> = (queue.dispatch =
(dispatchSetState.bind(null, currentlyRenderingFiber, queue): any));
return [hook.memoizedState, dispatch];
}
function updateState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
return updateReducer(basicStateReducer, (initialState: any));
}
function rerenderState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
return rerenderReducer(basicStateReducer, (initialState: any));
}
function pushEffect(
tag: HookFlags,
create: () => (() => void) | void,
destroy: (() => void) | void,
deps: Array<mixed> | void | null,
): Effect {
const effect: Effect = {
tag,
create,
destroy,
deps,
next: (null: any),
};
let componentUpdateQueue: null | FunctionComponentUpdateQueue =
(currentlyRenderingFiber.updateQueue: any);
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = (componentUpdateQueue: any);
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
const lastEffect = componentUpdateQueue.lastEffect;
if (lastEffect === null) {
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
const firstEffect = lastEffect.next;
lastEffect.next = effect;
effect.next = firstEffect;
componentUpdateQueue.lastEffect = effect;
}
}
return effect;
}
let stackContainsErrorMessage: boolean | null = null;
function getCallerStackFrame(): string {
const stackFrames = new Error('Error message').stack.split('\n');
if (stackContainsErrorMessage === null) {
stackContainsErrorMessage = stackFrames[0].includes('Error message');
}
return stackContainsErrorMessage
? stackFrames.slice(3, 4).join('\n')
: stackFrames.slice(2, 3).join('\n');
}
function mountRef<T>(initialValue: T): {current: T} {
const hook = mountWorkInProgressHook();
if (enableUseRefAccessWarning) {
if (__DEV__) {
let hasBeenInitialized = initialValue != null;
let lazyInitGetterStack = null;
let didCheckForLazyInit = false;
let didWarnAboutRead = false;
let didWarnAboutWrite = false;
let current = initialValue;
const ref = {
get current() {
if (!hasBeenInitialized) {
didCheckForLazyInit = true;
lazyInitGetterStack = getCallerStackFrame();
} else if (currentlyRenderingFiber !== null && !didWarnAboutRead) {
if (
lazyInitGetterStack === null ||
lazyInitGetterStack !== getCallerStackFrame()
) {
didWarnAboutRead = true;
console.warn(
'%s: Unsafe read of a mutable value during render.\n\n' +
'Reading from a ref during render is only safe if:\n' +
'1. The ref value has not been updated, or\n' +
'2. The ref holds a lazily-initialized value that is only set once.\n',
getComponentNameFromFiber(currentlyRenderingFiber) || 'Unknown',
);
}
}
return current;
},
set current(value: any) {
if (currentlyRenderingFiber !== null && !didWarnAboutWrite) {
if (hasBeenInitialized || !didCheckForLazyInit) {
didWarnAboutWrite = true;
console.warn(
'%s: Unsafe write of a mutable value during render.\n\n' +
'Writing to a ref during render is only safe if the ref holds ' +
'a lazily-initialized value that is only set once.\n',
getComponentNameFromFiber(currentlyRenderingFiber) || 'Unknown',
);
}
}
hasBeenInitialized = true;
current = value;
},
};
Object.seal(ref);
hook.memoizedState = ref;
return ref;
} else {
const ref = {current: initialValue};
hook.memoizedState = ref;
return ref;
}
} else {
const ref = {current: initialValue};
hook.memoizedState = ref;
return ref;
}
}
function updateRef<T>(initialValue: T): {current: T} {
const hook = updateWorkInProgressHook();
return hook.memoizedState;
}
function mountEffectImpl(
fiberFlags: Flags,
hookFlags: HookFlags,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
undefined,
nextDeps,
);
}
function updateEffectImpl(
fiberFlags: Flags,
hookFlags: HookFlags,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
let destroy = undefined;
if (currentHook !== null) {
const prevEffect = currentHook.memoizedState;
destroy = prevEffect.destroy;
if (nextDeps !== null) {
const prevDeps = prevEffect.deps;
if (areHookInputsEqual(nextDeps, prevDeps)) {
hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps);
return;
}
}
}
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
destroy,
nextDeps,
);
}
function mountEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
if (
__DEV__ &&
(currentlyRenderingFiber.mode & StrictEffectsMode) !== NoMode
) {
mountEffectImpl(
MountPassiveDevEffect | PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
deps,
);
} else {
mountEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
deps,
);
}
}
function updateEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}
function useEffectEventImpl<Args, Return, F: (...Array<Args>) => Return>(
payload: EventFunctionPayload<Args, Return, F>,
) {
currentlyRenderingFiber.flags |= UpdateEffect;
let componentUpdateQueue: null | FunctionComponentUpdateQueue =
(currentlyRenderingFiber.updateQueue: any);
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = (componentUpdateQueue: any);
componentUpdateQueue.events = [payload];
} else {
const events = componentUpdateQueue.events;
if (events === null) {
componentUpdateQueue.events = [payload];
} else {
events.push(payload);
}
}
}
function mountEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
const hook = mountWorkInProgressHook();
const ref = {impl: callback};
hook.memoizedState = ref;
return function eventFn() {
if (isInvalidExecutionContextForEventFunction()) {
throw new Error(
"A function wrapped in useEffectEvent can't be called during rendering.",
);
}
return ref.impl.apply(undefined, arguments);
};
}
function updateEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
const hook = updateWorkInProgressHook();
const ref = hook.memoizedState;
useEffectEventImpl({ref, nextImpl: callback});
return function eventFn() {
if (isInvalidExecutionContextForEventFunction()) {
throw new Error(
"A function wrapped in useEffectEvent can't be called during rendering.",
);
}
return ref.impl.apply(undefined, arguments);
};
}
function mountInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
mountEffectImpl(UpdateEffect, HookInsertion, create, deps);
}
function updateInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
return updateEffectImpl(UpdateEffect, HookInsertion, create, deps);
}
function mountLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
let fiberFlags: Flags = UpdateEffect | LayoutStaticEffect;
if (
__DEV__ &&
(currentlyRenderingFiber.mode & StrictEffectsMode) !== NoMode
) {
fiberFlags |= MountLayoutDevEffect;
}
return mountEffectImpl(fiberFlags, HookLayout, create, deps);
}
function updateLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
}
function imperativeHandleEffect<T>(
create: () => T,
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
): void | (() => void) {
if (typeof ref === 'function') {
const refCallback = ref;
const inst = create();
refCallback(inst);
return () => {
refCallback(null);
};
} else if (ref !== null && ref !== undefined) {
const refObject = ref;
if (__DEV__) {
if (!refObject.hasOwnProperty('current')) {
console.error(
'Expected useImperativeHandle() first argument to either be a ' +
'ref callback or React.createRef() object. Instead received: %s.',
'an object with keys {' + Object.keys(refObject).join(', ') + '}',
);
}
}
const inst = create();
refObject.current = inst;
return () => {
refObject.current = null;
};
}
}
function mountImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
if (__DEV__) {
if (typeof create !== 'function') {
console.error(
'Expected useImperativeHandle() second argument to be a function ' +
'that creates a handle. Instead received: %s.',
create !== null ? typeof create : 'null',
);
}
}
const effectDeps =
deps !== null && deps !== undefined ? deps.concat([ref]) : null;
let fiberFlags: Flags = UpdateEffect | LayoutStaticEffect;
if (
__DEV__ &&
(currentlyRenderingFiber.mode & StrictEffectsMode) !== NoMode
) {
fiberFlags |= MountLayoutDevEffect;
}
mountEffectImpl(
fiberFlags,
HookLayout,
imperativeHandleEffect.bind(null, create, ref),
effectDeps,
);
}
function updateImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
if (__DEV__) {
if (typeof create !== 'function') {
console.error(
'Expected useImperativeHandle() second argument to be a function ' +
'that creates a handle. Instead received: %s.',
create !== null ? typeof create : 'null',
);
}
}
const effectDeps =
deps !== null && deps !== undefined ? deps.concat([ref]) : null;
updateEffectImpl(
UpdateEffect,
HookLayout,
imperativeHandleEffect.bind(null, create, ref),
effectDeps,
);
}
function mountDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
}
const updateDebugValue = mountDebugValue;
function mountCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
hook.memoizedState = [callback, nextDeps];
return callback;
}
function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (nextDeps !== null) {
const prevDeps: Array<mixed> | null = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}
function mountMemo<T>(
nextCreate: () => T,
deps: Array<mixed> | void | null,
): T {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
if (shouldDoubleInvokeUserFnsInHooksDEV) {
nextCreate();
}
const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function updateMemo<T>(
nextCreate: () => T,
deps: Array<mixed> | void | null,
): T {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (nextDeps !== null) {
const prevDeps: Array<mixed> | null = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
if (shouldDoubleInvokeUserFnsInHooksDEV) {
nextCreate();
}
const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function mountDeferredValue<T>(value: T): T {
const hook = mountWorkInProgressHook();
hook.memoizedState = value;
return value;
}
function updateDeferredValue<T>(value: T): T {
const hook = updateWorkInProgressHook();
const resolvedCurrentHook: Hook = (currentHook: any);
const prevValue: T = resolvedCurrentHook.memoizedState;
return updateDeferredValueImpl(hook, prevValue, value);
}
function rerenderDeferredValue<T>(value: T): T {
const hook = updateWorkInProgressHook();
if (currentHook === null) {
hook.memoizedState = value;
return value;
} else {
const prevValue: T = currentHook.memoizedState;
return updateDeferredValueImpl(hook, prevValue, value);
}
}
function updateDeferredValueImpl<T>(hook: Hook, prevValue: T, value: T): T {
const shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);
if (shouldDeferValue) {
if (!is(value, prevValue)) {
const deferredLane = claimNextTransitionLane();
currentlyRenderingFiber.lanes = mergeLanes(
currentlyRenderingFiber.lanes,
deferredLane,
);
markSkippedUpdateLanes(deferredLane);
hook.baseState = true;
}
return prevValue;
} else {
if (hook.baseState) {
hook.baseState = false;
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = value;
return value;
}
}
function startTransition(
setPending: boolean => void,
callback: () => void,
options?: StartTransitionOptions,
): void {
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(
higherEventPriority(previousPriority, ContinuousEventPriority),
);
const prevTransition = ReactCurrentBatchConfig.transition;
ReactCurrentBatchConfig.transition = null;
setPending(true);
const currentTransition = (ReactCurrentBatchConfig.transition =
({}: BatchConfigTransition));
if (enableTransitionTracing) {
if (options !== undefined && options.name !== undefined) {
ReactCurrentBatchConfig.transition.name = options.name;
ReactCurrentBatchConfig.transition.startTime = now();
}
}
if (__DEV__) {
ReactCurrentBatchConfig.transition._updatedFibers = new Set();
}
try {
setPending(false);
callback();
} finally {
setCurrentUpdatePriority(previousPriority);
ReactCurrentBatchConfig.transition = prevTransition;
if (__DEV__) {
if (prevTransition === null && currentTransition._updatedFibers) {
const updatedFibersCount = currentTransition._updatedFibers.size;
currentTransition._updatedFibers.clear();
if (updatedFibersCount > 10) {
console.warn(
'Detected a large number of updates inside startTransition. ' +
'If this is due to a subscription please re-write it to use React provided hooks. ' +
'Otherwise concurrent mode guarantees are off the table.',
);
}
}
}
}
}
function mountTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
] {
const [isPending, setPending] = mountState(false);
const start = startTransition.bind(null, setPending);
const hook = mountWorkInProgressHook();
hook.memoizedState = start;
return [isPending, start];
}
function updateTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
] {
const [isPending] = updateState(false);
const hook = updateWorkInProgressHook();
const start = hook.memoizedState;
return [isPending, start];
}
function rerenderTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
] {
const [isPending] = rerenderState(false);
const hook = updateWorkInProgressHook();
const start = hook.memoizedState;
return [isPending, start];
}
function mountId(): string {
const hook = mountWorkInProgressHook();
const root = ((getWorkInProgressRoot(): any): FiberRoot);
const identifierPrefix = root.identifierPrefix;
let id;
if (getIsHydrating()) {
const treeId = getTreeId();
id = ':' + identifierPrefix + 'R' + treeId;
const localId = localIdCounter++;
if (localId > 0) {
id += 'H' + localId.toString(32);
}
id += ':';
} else {
const globalClientId = globalClientIdCounter++;
id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':';
}
hook.memoizedState = id;
return id;
}
function updateId(): string {
const hook = updateWorkInProgressHook();
const id: string = hook.memoizedState;
return id;
}
function mountRefresh(): any {
const hook = mountWorkInProgressHook();
const refresh = (hook.memoizedState = refreshCache.bind(
null,
currentlyRenderingFiber,
));
return refresh;
}
function updateRefresh(): any {
const hook = updateWorkInProgressHook();
return hook.memoizedState;
}
function refreshCache<T>(fiber: Fiber, seedKey: ?() => T, seedValue: T): void {
if (!enableCache) {
return;
}
let provider = fiber.return;
while (provider !== null) {
switch (provider.tag) {
case CacheComponent:
case HostRoot: {
const lane = requestUpdateLane(provider);
const refreshUpdate = createLegacyQueueUpdate(lane);
const root = enqueueLegacyQueueUpdate(provider, refreshUpdate, lane);
if (root !== null) {
const eventTime = requestEventTime();
scheduleUpdateOnFiber(root, provider, lane, eventTime);
entangleLegacyQueueTransitions(root, provider, lane);
}
const seededCache = createCache();
if (seedKey !== null && seedKey !== undefined && root !== null) {
if (enableLegacyCache) {
seededCache.data.set(seedKey, seedValue);
} else {
if (__DEV__) {
console.error(
'The seed argument is not enabled outside experimental channels.',
);
}
}
}
const payload = {
cache: seededCache,
};
refreshUpdate.payload = payload;
return;
}
}
provider = provider.return;
}
}
function dispatchReducerAction<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
): void {
if (__DEV__) {
if (typeof arguments[3] === 'function') {
console.error(
"State updates from the useState() and useReducer() Hooks don't support the " +
'second callback argument. To execute a side effect after ' +
'rendering, declare it in the component body with useEffect().',
);
}
}
const lane = requestUpdateLane(fiber);
const update: Update<S, A> = {
lane,
action,
hasEagerState: false,
eagerState: null,
next: (null: any),
};
if (isRenderPhaseUpdate(fiber)) {
enqueueRenderPhaseUpdate(queue, update);
} else {
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
const eventTime = requestEventTime();
scheduleUpdateOnFiber(root, fiber, lane, eventTime);
entangleTransitionUpdate(root, queue, lane);
}
}
markUpdateInDevTools(fiber, lane, action);
}
function dispatchSetState<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
): void {
if (__DEV__) {
if (typeof arguments[3] === 'function') {
console.error(
"State updates from the useState() and useReducer() Hooks don't support the " +
'second callback argument. To execute a side effect after ' +
'rendering, declare it in the component body with useEffect().',
);
}
}
const lane = requestUpdateLane(fiber);
const update: Update<S, A> = {
lane,
action,
hasEagerState: false,
eagerState: null,
next: (null: any),
};
if (isRenderPhaseUpdate(fiber)) {
enqueueRenderPhaseUpdate(queue, update);
} else {
const alternate = fiber.alternate;
if (
fiber.lanes === NoLanes &&
(alternate === null || alternate.lanes === NoLanes)
) {
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
let prevDispatcher;
if (__DEV__) {
prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
}
try {
const currentState: S = (queue.lastRenderedState: any);
const eagerState = lastRenderedReducer(currentState, action);
update.hasEagerState = true;
update.eagerState = eagerState;
if (is(eagerState, currentState)) {
enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update);
return;
}
} catch (error) {
} finally {
if (__DEV__) {
ReactCurrentDispatcher.current = prevDispatcher;
}
}
}
}
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
const eventTime = requestEventTime();
scheduleUpdateOnFiber(root, fiber, lane, eventTime);
entangleTransitionUpdate(root, queue, lane);
}
}
markUpdateInDevTools(fiber, lane, action);
}
function isRenderPhaseUpdate(fiber: Fiber): boolean {
const alternate = fiber.alternate;
return (
fiber === currentlyRenderingFiber ||
(alternate !== null && alternate === currentlyRenderingFiber)
);
}
function enqueueRenderPhaseUpdate<S, A>(
queue: UpdateQueue<S, A>,
update: Update<S, A>,
): void {
didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate =
true;
const pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
}
function entangleTransitionUpdate<S, A>(
root: FiberRoot,
queue: UpdateQueue<S, A>,
lane: Lane,
): void {
if (isTransitionLane(lane)) {
let queueLanes = queue.lanes;
queueLanes = intersectLanes(queueLanes, root.pendingLanes);
const newQueueLanes = mergeLanes(queueLanes, lane);
queue.lanes = newQueueLanes;
markRootEntangled(root, newQueueLanes);
}
}
function markUpdateInDevTools<A>(fiber: Fiber, lane: Lane, action: A): void {
if (__DEV__) {
if (enableDebugTracing) {
if (fiber.mode & DebugTracingMode) {
const name = getComponentNameFromFiber(fiber) || 'Unknown';
logStateUpdateScheduled(name, lane, action);
}
}
}
if (enableSchedulingProfiler) {
markStateUpdateScheduled(fiber, lane);
}
}
export const ContextOnlyDispatcher: Dispatcher = {
readContext,
useCallback: throwInvalidHookError,
useContext: throwInvalidHookError,
useEffect: throwInvalidHookError,
useImperativeHandle: throwInvalidHookError,
useInsertionEffect: throwInvalidHookError,
useLayoutEffect: throwInvalidHookError,
useMemo: throwInvalidHookError,
useReducer: throwInvalidHookError,
useRef: throwInvalidHookError,
useState: throwInvalidHookError,
useDebugValue: throwInvalidHookError,
useDeferredValue: throwInvalidHookError,
useTransition: throwInvalidHookError,
useMutableSource: throwInvalidHookError,
useSyncExternalStore: throwInvalidHookError,
useId: throwInvalidHookError,
};
if (enableCache) {
(ContextOnlyDispatcher: Dispatcher).useCacheRefresh = throwInvalidHookError;
}
if (enableUseHook) {
(ContextOnlyDispatcher: Dispatcher).use = throwInvalidHookError;
}
if (enableUseMemoCacheHook) {
(ContextOnlyDispatcher: Dispatcher).useMemoCache = throwInvalidHookError;
}
if (enableUseEffectEventHook) {
(ContextOnlyDispatcher: Dispatcher).useEffectEvent = throwInvalidHookError;
}
const HooksDispatcherOnMount: Dispatcher = {
readContext,
useCallback: mountCallback,
useContext: readContext,
useEffect: mountEffect,
useImperativeHandle: mountImperativeHandle,
useLayoutEffect: mountLayoutEffect,
useInsertionEffect: mountInsertionEffect,
useMemo: mountMemo,
useReducer: mountReducer,
useRef: mountRef,
useState: mountState,
useDebugValue: mountDebugValue,
useDeferredValue: mountDeferredValue,
useTransition: mountTransition,
useMutableSource: mountMutableSource,
useSyncExternalStore: mountSyncExternalStore,
useId: mountId,
};
if (enableCache) {
(HooksDispatcherOnMount: Dispatcher).useCacheRefresh = mountRefresh;
}
if (enableUseHook) {
(HooksDispatcherOnMount: Dispatcher).use = use;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnMount: Dispatcher).useMemoCache = useMemoCache;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnMount: Dispatcher).useEffectEvent = mountEvent;
}
const HooksDispatcherOnUpdate: Dispatcher = {
readContext,
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useImperativeHandle: updateImperativeHandle,
useInsertionEffect: updateInsertionEffect,
useLayoutEffect: updateLayoutEffect,
useMemo: updateMemo,
useReducer: updateReducer,
useRef: updateRef,
useState: updateState,
useDebugValue: updateDebugValue,
useDeferredValue: updateDeferredValue,
useTransition: updateTransition,
useMutableSource: updateMutableSource,
useSyncExternalStore: updateSyncExternalStore,
useId: updateId,
};
if (enableCache) {
(HooksDispatcherOnUpdate: Dispatcher).useCacheRefresh = updateRefresh;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnUpdate: Dispatcher).useMemoCache = useMemoCache;
}
if (enableUseHook) {
(HooksDispatcherOnUpdate: Dispatcher).use = use;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnUpdate: Dispatcher).useEffectEvent = updateEvent;
}
const HooksDispatcherOnRerender: Dispatcher = {
readContext,
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useImperativeHandle: updateImperativeHandle,
useInsertionEffect: updateInsertionEffect,
useLayoutEffect: updateLayoutEffect,
useMemo: updateMemo,
useReducer: rerenderReducer,
useRef: updateRef,
useState: rerenderState,
useDebugValue: updateDebugValue,
useDeferredValue: rerenderDeferredValue,
useTransition: rerenderTransition,
useMutableSource: updateMutableSource,
useSyncExternalStore: updateSyncExternalStore,
useId: updateId,
};
if (enableCache) {
(HooksDispatcherOnRerender: Dispatcher).useCacheRefresh = updateRefresh;
}
if (enableUseHook) {
(HooksDispatcherOnRerender: Dispatcher).use = use;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnRerender: Dispatcher).useMemoCache = useMemoCache;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnRerender: Dispatcher).useEffectEvent = updateEvent;
}
let HooksDispatcherOnMountInDEV: Dispatcher | null = null;
let HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher | null = null;
let HooksDispatcherOnUpdateInDEV: Dispatcher | null = null;
let HooksDispatcherOnRerenderInDEV: Dispatcher | null = null;
let InvalidNestedHooksDispatcherOnMountInDEV: Dispatcher | null = null;
let InvalidNestedHooksDispatcherOnUpdateInDEV: Dispatcher | null = null;
let InvalidNestedHooksDispatcherOnRerenderInDEV: Dispatcher | null = null;
if (__DEV__) {
const warnInvalidContextAccess = () => {
console.error(
'Context can only be read while React is rendering. ' +
'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
'In function components, you can read it directly in the function body, but not ' +
'inside Hooks like useReducer() or useMemo().',
);
};
const warnInvalidHookAccess = () => {
console.error(
'Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' +
'You can only call Hooks at the top level of your React function. ' +
'For more information, see ' +
'https://reactjs.org/link/rules-of-hooks',
);
};
HooksDispatcherOnMountInDEV = {
readContext<T>(context: ReactContext<T>): T {
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
mountHookTypesDev();
checkDepsAreArrayDev(deps);
return mountCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
mountHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
mountHookTypesDev();
checkDepsAreArrayDev(deps);
return mountEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
mountHookTypesDev();
checkDepsAreArrayDev(deps);
return mountImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
mountHookTypesDev();
checkDepsAreArrayDev(deps);
return mountInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
mountHookTypesDev();
checkDepsAreArrayDev(deps);
return mountLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
mountHookTypesDev();
checkDepsAreArrayDev(deps);
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
mountHookTypesDev();
return mountRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
mountHookTypesDev();
return mountDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
mountHookTypesDev();
return mountDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
mountHookTypesDev();
return mountTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
mountHookTypesDev();
return mountMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
mountHookTypesDev();
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
mountHookTypesDev();
return mountId();
},
};
if (enableCache) {
(HooksDispatcherOnMountInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
mountHookTypesDev();
return mountRefresh();
};
}
if (enableUseHook) {
(HooksDispatcherOnMountInDEV: Dispatcher).use = use;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnMountInDEV: Dispatcher).useMemoCache = useMemoCache;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnMountInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
mountHookTypesDev();
return mountEvent(callback);
};
}
HooksDispatcherOnMountWithHookTypesInDEV = {
readContext<T>(context: ReactContext<T>): T {
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return mountCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
updateHookTypesDev();
return mountEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
updateHookTypesDev();
return mountImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
updateHookTypesDev();
return mountInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
updateHookTypesDev();
return mountLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
updateHookTypesDev();
return mountRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
updateHookTypesDev();
return mountDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
updateHookTypesDev();
return mountDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
updateHookTypesDev();
return mountTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
updateHookTypesDev();
return mountMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
updateHookTypesDev();
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
updateHookTypesDev();
return mountId();
},
};
if (enableCache) {
(HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
updateHookTypesDev();
return mountRefresh();
};
}
if (enableUseHook) {
(HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher).use = use;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher).useMemoCache =
useMemoCache;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
updateHookTypesDev();
return mountEvent(callback);
};
}
HooksDispatcherOnUpdateInDEV = {
readContext<T>(context: ReactContext<T>): T {
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return updateCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
updateHookTypesDev();
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
updateHookTypesDev();
return updateImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
updateHookTypesDev();
return updateInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
updateHookTypesDev();
return updateLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
updateHookTypesDev();
return updateRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
updateHookTypesDev();
return updateDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
updateHookTypesDev();
return updateDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
updateHookTypesDev();
return updateTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
updateHookTypesDev();
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
updateHookTypesDev();
return updateId();
},
};
if (enableCache) {
(HooksDispatcherOnUpdateInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
updateHookTypesDev();
return updateRefresh();
};
}
if (enableUseHook) {
(HooksDispatcherOnUpdateInDEV: Dispatcher).use = use;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnUpdateInDEV: Dispatcher).useMemoCache = useMemoCache;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnUpdateInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
updateHookTypesDev();
return updateEvent(callback);
};
}
HooksDispatcherOnRerenderInDEV = {
readContext<T>(context: ReactContext<T>): T {
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return updateCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
updateHookTypesDev();
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
updateHookTypesDev();
return updateImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
updateHookTypesDev();
return updateInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
updateHookTypesDev();
return updateLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnRerenderInDEV;
try {
return updateMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnRerenderInDEV;
try {
return rerenderReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
updateHookTypesDev();
return updateRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnRerenderInDEV;
try {
return rerenderState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
updateHookTypesDev();
return updateDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
updateHookTypesDev();
return rerenderDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
updateHookTypesDev();
return rerenderTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
updateHookTypesDev();
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
updateHookTypesDev();
return updateId();
},
};
if (enableCache) {
(HooksDispatcherOnRerenderInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
updateHookTypesDev();
return updateRefresh();
};
}
if (enableUseHook) {
(HooksDispatcherOnRerenderInDEV: Dispatcher).use = use;
}
if (enableUseMemoCacheHook) {
(HooksDispatcherOnRerenderInDEV: Dispatcher).useMemoCache = useMemoCache;
}
if (enableUseEffectEventHook) {
(HooksDispatcherOnRerenderInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
updateHookTypesDev();
return updateEvent(callback);
};
}
InvalidNestedHooksDispatcherOnMountInDEV = {
readContext<T>(context: ReactContext<T>): T {
warnInvalidContextAccess();
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
warnInvalidHookAccess();
mountHookTypesDev();
return mountCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
mountHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
warnInvalidHookAccess();
mountHookTypesDev();
return mountEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
warnInvalidHookAccess();
mountHookTypesDev();
return mountImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
warnInvalidHookAccess();
mountHookTypesDev();
return mountInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
warnInvalidHookAccess();
mountHookTypesDev();
return mountLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
warnInvalidHookAccess();
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
warnInvalidHookAccess();
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
warnInvalidHookAccess();
mountHookTypesDev();
return mountRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
warnInvalidHookAccess();
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
warnInvalidHookAccess();
mountHookTypesDev();
return mountDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
warnInvalidHookAccess();
mountHookTypesDev();
return mountDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
warnInvalidHookAccess();
mountHookTypesDev();
return mountTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
warnInvalidHookAccess();
mountHookTypesDev();
return mountMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
warnInvalidHookAccess();
mountHookTypesDev();
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
warnInvalidHookAccess();
mountHookTypesDev();
return mountId();
},
};
if (enableCache) {
(InvalidNestedHooksDispatcherOnMountInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
mountHookTypesDev();
return mountRefresh();
};
}
if (enableUseHook) {
(InvalidNestedHooksDispatcherOnMountInDEV: Dispatcher).use = function <T>(
usable: Usable<T>,
): T {
warnInvalidHookAccess();
return use(usable);
};
}
if (enableUseMemoCacheHook) {
(InvalidNestedHooksDispatcherOnMountInDEV: Dispatcher).useMemoCache =
function (size: number): Array<any> {
warnInvalidHookAccess();
return useMemoCache(size);
};
}
if (enableUseEffectEventHook) {
(InvalidNestedHooksDispatcherOnMountInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
warnInvalidHookAccess();
mountHookTypesDev();
return mountEvent(callback);
};
}
InvalidNestedHooksDispatcherOnUpdateInDEV = {
readContext<T>(context: ReactContext<T>): T {
warnInvalidContextAccess();
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
warnInvalidHookAccess();
updateHookTypesDev();
return updateCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
updateHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
warnInvalidHookAccess();
updateHookTypesDev();
return updateImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
warnInvalidHookAccess();
updateHookTypesDev();
return updateInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
warnInvalidHookAccess();
updateHookTypesDev();
return updateLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
warnInvalidHookAccess();
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
warnInvalidHookAccess();
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
warnInvalidHookAccess();
updateHookTypesDev();
return updateRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
warnInvalidHookAccess();
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
warnInvalidHookAccess();
updateHookTypesDev();
return updateDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
warnInvalidHookAccess();
updateHookTypesDev();
return updateDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
warnInvalidHookAccess();
updateHookTypesDev();
return updateTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
warnInvalidHookAccess();
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
warnInvalidHookAccess();
updateHookTypesDev();
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
warnInvalidHookAccess();
updateHookTypesDev();
return updateId();
},
};
if (enableCache) {
(InvalidNestedHooksDispatcherOnUpdateInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
updateHookTypesDev();
return updateRefresh();
};
}
if (enableUseHook) {
(InvalidNestedHooksDispatcherOnUpdateInDEV: Dispatcher).use = function <T>(
usable: Usable<T>,
): T {
warnInvalidHookAccess();
return use(usable);
};
}
if (enableUseMemoCacheHook) {
(InvalidNestedHooksDispatcherOnUpdateInDEV: Dispatcher).useMemoCache =
function (size: number): Array<any> {
warnInvalidHookAccess();
return useMemoCache(size);
};
}
if (enableUseEffectEventHook) {
(InvalidNestedHooksDispatcherOnUpdateInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEvent(callback);
};
}
InvalidNestedHooksDispatcherOnRerenderInDEV = {
readContext<T>(context: ReactContext<T>): T {
warnInvalidContextAccess();
return readContext(context);
},
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useCallback';
warnInvalidHookAccess();
updateHookTypesDev();
return updateCallback(callback, deps);
},
useContext<T>(context: ReactContext<T>): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
updateHookTypesDev();
return readContext(context);
},
useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useImperativeHandle';
warnInvalidHookAccess();
updateHookTypesDev();
return updateImperativeHandle(ref, create, deps);
},
useInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useInsertionEffect';
warnInvalidHookAccess();
updateHookTypesDev();
return updateInsertionEffect(create, deps);
},
useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useLayoutEffect';
warnInvalidHookAccess();
updateHookTypesDev();
return updateLayoutEffect(create, deps);
},
useMemo<T>(create: () => T, deps: Array<mixed> | void | null): T {
currentHookNameInDev = 'useMemo';
warnInvalidHookAccess();
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return updateMemo(create, deps);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
currentHookNameInDev = 'useReducer';
warnInvalidHookAccess();
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return rerenderReducer(reducer, initialArg, init);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useRef<T>(initialValue: T): {current: T} {
currentHookNameInDev = 'useRef';
warnInvalidHookAccess();
updateHookTypesDev();
return updateRef(initialValue);
},
useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
warnInvalidHookAccess();
updateHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current =
InvalidNestedHooksDispatcherOnUpdateInDEV;
try {
return rerenderState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
},
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void {
currentHookNameInDev = 'useDebugValue';
warnInvalidHookAccess();
updateHookTypesDev();
return updateDebugValue(value, formatterFn);
},
useDeferredValue<T>(value: T): T {
currentHookNameInDev = 'useDeferredValue';
warnInvalidHookAccess();
updateHookTypesDev();
return rerenderDeferredValue(value);
},
useTransition(): [boolean, (() => void) => void] {
currentHookNameInDev = 'useTransition';
warnInvalidHookAccess();
updateHookTypesDev();
return rerenderTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
warnInvalidHookAccess();
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
currentHookNameInDev = 'useSyncExternalStore';
warnInvalidHookAccess();
updateHookTypesDev();
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
},
useId(): string {
currentHookNameInDev = 'useId';
warnInvalidHookAccess();
updateHookTypesDev();
return updateId();
},
};
if (enableCache) {
(InvalidNestedHooksDispatcherOnRerenderInDEV: Dispatcher).useCacheRefresh =
function useCacheRefresh() {
currentHookNameInDev = 'useCacheRefresh';
updateHookTypesDev();
return updateRefresh();
};
}
if (enableUseHook) {
(InvalidNestedHooksDispatcherOnRerenderInDEV: Dispatcher).use = function <
T,
>(usable: Usable<T>): T {
warnInvalidHookAccess();
return use(usable);
};
}
if (enableUseMemoCacheHook) {
(InvalidNestedHooksDispatcherOnRerenderInDEV: Dispatcher).useMemoCache =
function (size: number): Array<any> {
warnInvalidHookAccess();
return useMemoCache(size);
};
}
if (enableUseEffectEventHook) {
(InvalidNestedHooksDispatcherOnRerenderInDEV: Dispatcher).useEffectEvent =
function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
callback: F,
): F {
currentHookNameInDev = 'useEffectEvent';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEvent(callback);
};
}
}