useMemoizedFn
useMemoizedFn
是持久化函数的 Hook,一般情况下,可以使用 useMemoizedFn
完全代替 useCallback
,特殊情况见 FAQ。
在某些场景中,我们需要使用 useCallback
来记住一个函数,但是在第二个参数 deps
变化时,会重新生成函数,导致函数地址变化。
类型声明
ts
declare function useMemoizedFn<T extends noop>(fn: T): T;
源码
ts
import { useMemo, useRef } from 'react';
import { isFunction } from '../utils';
import isDev from '../utils/isDev';
type noop = (this: any, ...args: any[]) => any;
type PickFunction<T extends noop> = (
this: ThisParameterType<T>,
...args: Parameters<T>
) => ReturnType<T>;
function useMemoizedFn<T extends noop>(fn: T) {
if (isDev) {
if (!isFunction(fn)) {
console.error(`useMemoizedFn expected parameter is a function, got ${typeof fn}`);
}
}
const fnRef = useRef<T>(fn);
// why not write `fnRef.current = fn`?
// https://github.com/alibaba/hooks/issues/728
fnRef.current = useMemo<T>(() => fn, [fn]);
const memoizedFn = useRef<PickFunction<T>>();
if (!memoizedFn.current) {
memoizedFn.current = function (this, ...args) {
return fnRef.current.apply(this, args);
};
}
return memoizedFn.current as T;
}
export default useMemoizedFn;
FAQ
useMemoizedFn
返回的函数没有继承 fn
自身的属性?
useMemoizedFn
返回的函数与传入的 fn
的引用完全不同,且没有继承 fn
自身的属性。如果想要持久化后函数自身的属性不丢失,目前 useMemoizedFn
满足不了,请降级使用 useCallback
、useMemo
。
相关问题:#2273。