useCallback使用陷阱,你知道吗🤨
2021-11-05 本文已影响0人
前端小白的摸爬滚打
问题
useCallback和useMemo在起到缓存作用的时候我们需要注意的是,我们传入的函数也是具有闭包的效果的,也就是说,他们如果使用到了一些状态的时候也只能拿到当时函数执行的状态,所以我们需要把useMemo和useCallback中依赖的state作为他们的依赖项传入,以防止他们拿到的值是旧的值。
useCallback的缺点:
- 记忆效果差,依赖变化时,函数也被重新生成
- 想要记忆效果好(也就是依赖为[])又拿不到最新的state
- useCallback返回的函数也是具有闭包效应即我们在其他hooks中使用的时候useCallback返回的函数也是那次闭包环境下产生的函数
那么我们就会想:怎么可以让我们传入的函数返回一个引用一直不变且可以让传入的函数内部所使用的state都是最新的呢?很多人都会想到一个hook --- useRef
实现
import { useRef } from 'react';
export function useNewContextFn(fn: Function) {
const fnRef = useRef(fn);
// 每次组件更新时都更新fnRef的current属性,可以让我们的函数拿到最新的上下文
fnRef.current = fn;
const cacheRef = useRef((...args: any[]) => fn.current(...args));
return cacheRef.current;
}
进阶版本,也许我们想要更多的函数都可以又这个效果
export default function useMethods<T extends Record<string, (...args: any[]) => any>>(methods: T) {
const { current } = React.useRef({
methods,
func: undefined as T | undefined,
});
current.methods = methods;
// 只初始化一次
if (!current.func) {
const func = Object.create(null);
Object.keys(methods).forEach((key) => {
// 包裹 function 转发调用最新的 methods
func[key] = (...args: unknown[]) => current.methods[key].call(current.methods, ...args);
});
// 返回给使用方的变量
current.func = func;
}
return current.func as T;
}
其实原理是一样的,看懂简易版本即可。😁