概要
以我的理解,函数式编程的优点是可以限制函数为无副作用的纯函数,但是如何解决状态等副作用的需求呢,那就要通过闭包让函数使用外部的变量,而管理和创建外部变量的api就称为hooks。
details
react hooks
packages/react/src/ReactHooks.js
useState
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
useEffect
export function useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useEffect(create, deps);
}
useContext/createContext
export function useContext<T>(Context: ReactContext<T>): T {
const dispatcher = resolveDispatcher();
if (__DEV__) {
// TODO: add a more generic warning for invalid values.
if ((Context: any)._context !== undefined) {
const realContext = (Context: any)._context;
// Don't deduplicate because this legitimately causes bugs
// and nobody should be using this in existing code.
if (realContext.Consumer === Context) {
console.error(
'Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be ' +
'removed in a future major release. Did you mean to call useContext(Context) instead?',
);
} else if (realContext.Provider === Context) {
console.error(
'Calling useContext(Context.Provider) is not supported. ' +
'Did you mean to call useContext(Context) instead?',
);
}
}
}
return dispatcher.useContext(Context);
}
useReducer
export function useReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const dispatcher = resolveDispatcher();
return dispatcher.useReducer(reducer, initialArg, init);
}
useMemo
export function useMemo<T>(
create: () => T,
deps: Array<mixed> | void | null,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useMemo(create, deps);
}
useCallback
export function useCallback<T>(
callback: T,
deps: Array<mixed> | void | null,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useCallback(callback, deps);
}
useRef
export function useRef<T>(initialValue: T): {current: T} {
const dispatcher = resolveDispatcher();
return dispatcher.useRef(initialValue);
}
useImperativeHandle/forwardRef
export function useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
create: () => T,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useImperativeHandle(ref, create, deps);
}
useLayoutEffect
export function useLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher();
return dispatcher.useLayoutEffect(create, deps);
}
useSyncExternalStore
export function useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
const dispatcher = resolveDispatcher();
return dispatcher.useSyncExternalStore(
subscribe,
getSnapshot,
getServerSnapshot,
);
}
useTransition
export function useTransition(): [
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
] {
const dispatcher = resolveDispatcher();
return dispatcher.useTransition();
}
useDeferredValue
export function useDeferredValue<T>(value: T, initialValue?: T): T {
const dispatcher = resolveDispatcher();
return dispatcher.useDeferredValue(value, initialValue);
}
useId
export function useId(): string {
const dispatcher = resolveDispatcher();
return dispatcher.useId();
}
ahooks
api
function useRequestImplement<TData, TParams extends any[]>(
service: Service<TData, TParams>,
options: Options<TData, TParams> = {},
plugins: Plugin<TData, TParams>[] = [],
) {
fetchInstance.pluginImpls = plugins.map((p) => p(fetchInstance, fetchOptions));
}
core
plugin
const usePollingPlugin: Plugin<any, any[]>
const useRetryPlugin: Plugin<any, any[]>
other hooks
const useUpdate = () => {
const [, setState] = useState({});
return useCallback(() => setState({}), []);
};
function useLatest<T>(value: T) {
const ref = useRef(value);
ref.current = value;
return ref;
}
const useMount = (fn: () => void) => {
useEffect(() => {
fn?.();
}, []);
};
const useUnmount = (fn: () => void) => {
const fnRef = useLatest(fn);
useEffect(
() => () => {
fnRef.current();
},
[],
);
};