the actual react hooks file from github:facebook/react at commit ac7820a99efac29dcd5a69f6d2438f6d31b7abbf
ReactHooks.js
241 lines 6.9 kB view raw
1/** 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 * @flow 8 */ 9 10import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes'; 11import type { 12 ReactContext, 13 StartTransitionOptions, 14 Usable, 15 Awaited, 16} from 'shared/ReactTypes'; 17import {REACT_CONSUMER_TYPE} from 'shared/ReactSymbols'; 18 19import ReactSharedInternals from 'shared/ReactSharedInternals'; 20 21type BasicStateAction<S> = (S => S) | S; 22type Dispatch<A> = A => void; 23 24function resolveDispatcher() { 25 const dispatcher = ReactSharedInternals.H; 26 if (__DEV__) { 27 if (dispatcher === null) { 28 console.error( 29 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + 30 ' one of the following reasons:\n' + 31 '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + 32 '2. You might be breaking the Rules of Hooks\n' + 33 '3. You might have more than one copy of React in the same app\n' + 34 'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.', 35 ); 36 } 37 } 38 // Will result in a null access error if accessed outside render phase. We 39 // intentionally don't throw our own error because this is in a hot path. 40 // Also helps ensure this is inlined. 41 return ((dispatcher: any): Dispatcher); 42} 43 44export function getCacheForType<T>(resourceType: () => T): T { 45 const dispatcher = ReactSharedInternals.A; 46 if (!dispatcher) { 47 // If there is no dispatcher, then we treat this as not being cached. 48 return resourceType(); 49 } 50 return dispatcher.getCacheForType(resourceType); 51} 52 53export function useContext<T>(Context: ReactContext<T>): T { 54 const dispatcher = resolveDispatcher(); 55 if (__DEV__) { 56 if (Context.$$typeof === REACT_CONSUMER_TYPE) { 57 console.error( 58 'Calling useContext(Context.Consumer) is not supported and will cause bugs. ' + 59 'Did you mean to call useContext(Context) instead?', 60 ); 61 } 62 } 63 return dispatcher.useContext(Context); 64} 65 66export function useState<S>( 67 initialState: (() => S) | S, 68): [S, Dispatch<BasicStateAction<S>>] { 69 const dispatcher = resolveDispatcher(); 70 return dispatcher.useState(initialState); 71} 72 73export function useReducer<S, I, A>( 74 reducer: (S, A) => S, 75 initialArg: I, 76 init?: I => S, 77): [S, Dispatch<A>] { 78 const dispatcher = resolveDispatcher(); 79 return dispatcher.useReducer(reducer, initialArg, init); 80} 81 82export function useRef<T>(initialValue: T): {current: T} { 83 const dispatcher = resolveDispatcher(); 84 return dispatcher.useRef(initialValue); 85} 86 87export function useEffect( 88 create: () => (() => void) | void, 89 deps: Array<mixed> | void | null, 90): void { 91 if (__DEV__) { 92 if (create == null) { 93 console.warn( 94 'React Hook useEffect requires an effect callback. Did you forget to pass a callback to the hook?', 95 ); 96 } 97 } 98 99 const dispatcher = resolveDispatcher(); 100 return dispatcher.useEffect(create, deps); 101} 102 103export function useInsertionEffect( 104 create: () => (() => void) | void, 105 deps: Array<mixed> | void | null, 106): void { 107 if (__DEV__) { 108 if (create == null) { 109 console.warn( 110 'React Hook useInsertionEffect requires an effect callback. Did you forget to pass a callback to the hook?', 111 ); 112 } 113 } 114 115 const dispatcher = resolveDispatcher(); 116 return dispatcher.useInsertionEffect(create, deps); 117} 118 119export function useLayoutEffect( 120 create: () => (() => void) | void, 121 deps: Array<mixed> | void | null, 122): void { 123 if (__DEV__) { 124 if (create == null) { 125 console.warn( 126 'React Hook useLayoutEffect requires an effect callback. Did you forget to pass a callback to the hook?', 127 ); 128 } 129 } 130 131 const dispatcher = resolveDispatcher(); 132 return dispatcher.useLayoutEffect(create, deps); 133} 134 135export function useCallback<T>( 136 callback: T, 137 deps: Array<mixed> | void | null, 138): T { 139 const dispatcher = resolveDispatcher(); 140 return dispatcher.useCallback(callback, deps); 141} 142 143export function useMemo<T>( 144 create: () => T, 145 deps: Array<mixed> | void | null, 146): T { 147 const dispatcher = resolveDispatcher(); 148 return dispatcher.useMemo(create, deps); 149} 150 151export function useImperativeHandle<T>( 152 ref: {current: T | null} | ((inst: T | null) => mixed) | null | void, 153 create: () => T, 154 deps: Array<mixed> | void | null, 155): void { 156 const dispatcher = resolveDispatcher(); 157 return dispatcher.useImperativeHandle(ref, create, deps); 158} 159 160export function useDebugValue<T>( 161 value: T, 162 formatterFn: ?(value: T) => mixed, 163): void { 164 if (__DEV__) { 165 const dispatcher = resolveDispatcher(); 166 return dispatcher.useDebugValue(value, formatterFn); 167 } 168} 169 170export function useTransition(): [ 171 boolean, 172 (callback: () => void, options?: StartTransitionOptions) => void, 173] { 174 const dispatcher = resolveDispatcher(); 175 return dispatcher.useTransition(); 176} 177 178export function useDeferredValue<T>(value: T, initialValue?: T): T { 179 const dispatcher = resolveDispatcher(); 180 return dispatcher.useDeferredValue(value, initialValue); 181} 182 183export function useId(): string { 184 const dispatcher = resolveDispatcher(); 185 return dispatcher.useId(); 186} 187 188export function useSyncExternalStore<T>( 189 subscribe: (() => void) => () => void, 190 getSnapshot: () => T, 191 getServerSnapshot?: () => T, 192): T { 193 const dispatcher = resolveDispatcher(); 194 return dispatcher.useSyncExternalStore( 195 subscribe, 196 getSnapshot, 197 getServerSnapshot, 198 ); 199} 200 201export function useCacheRefresh(): <T>(?() => T, ?T) => void { 202 const dispatcher = resolveDispatcher(); 203 // $FlowFixMe[not-a-function] This is unstable, thus optional 204 return dispatcher.useCacheRefresh(); 205} 206 207export function use<T>(usable: Usable<T>): T { 208 const dispatcher = resolveDispatcher(); 209 return dispatcher.use(usable); 210} 211 212export function useMemoCache(size: number): Array<mixed> { 213 const dispatcher = resolveDispatcher(); 214 // $FlowFixMe[not-a-function] This is unstable, thus optional 215 return dispatcher.useMemoCache(size); 216} 217 218export function useEffectEvent<Args, F: (...Array<Args>) => mixed>( 219 callback: F, 220): F { 221 const dispatcher = resolveDispatcher(); 222 // $FlowFixMe[not-a-function] This is unstable, thus optional 223 return dispatcher.useEffectEvent(callback); 224} 225 226export function useOptimistic<S, A>( 227 passthrough: S, 228 reducer: ?(S, A) => S, 229): [S, (A) => void] { 230 const dispatcher = resolveDispatcher(); 231 return dispatcher.useOptimistic(passthrough, reducer); 232} 233 234export function useActionState<S, P>( 235 action: (Awaited<S>, P) => S, 236 initialState: Awaited<S>, 237 permalink?: string, 238): [Awaited<S>, (P) => void, boolean] { 239 const dispatcher = resolveDispatcher(); 240 return dispatcher.useActionState(action, initialState, permalink); 241}