useMemoizedFn
作用
持久化 function
的 Hook,理论上,可以使用 useMemoizedFn
完全代替 useCallback
。
在某些场景中,我们需要使用 useCallback
来记住一个函数,但是在第二个参数 deps
变化时,会重新生成函数,导致函数地址变化。
useMemoizedFn
会在 deps
变化时,返回一个新的函数,但是函数的地址不会变化。
原理
通过
useRef
保持function
引用地址不变,并且每次执行都可以拿到最新的state
值。
源码
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}`)
}
}
// 通过 useRef 保持其引用地址不变,并且值能够保持值最新
const fnRef = useRef<T>(fn)
// why not write `fnRef.current = fn`?
// https://github.com/alibaba/hooks/issues/728
fnRef.current = useMemo(() => fn, [fn])
// 通过 useRef 保持其引用地址不变,并且值能够保持值最新
const memoizedFn = useRef<PickFunction<T>>()
if (!memoizedFn.current) {
// 返回的持久化函数,调用该函数的时候,调用原始的函数,并且保持 this 指向不变
memoizedFn.current = function (this, ...args) {
return fnRef.current.apply(this, args)
}
}
return memoizedFn.current as T
}
export default useMemoizedFn