记忆化(Memoization),对于计算量大的函数,通过缓存它的返回值来节省计算时间,提升程序执行速度
useMemo 和 useCallback 做性能优化的原理就是记忆化,所以它们的本质和 useEffect 一样,都是在处理副作用
const memoized = useMemo(() => createByHeavyComputing(a, b), [a, b]);
// -------- ---------------------------------- ------
// ^ ^ ^
// | | |
// 工厂函数返回值 工厂函数 依赖值数组
useMemo 的功能是为工厂函数返回一个记忆化的计算值,在两次渲染之间,只有依赖值数组中的依赖值有变化时,该 Hook 才会调用工厂函数重新计算,将新的返回值记忆化并返回给组件
const [num, setNum] = useState('0');
const sum = useMemo(() => {
const n = parseInt(num, 10);
return fibonacci(n);
}, [num]);
状态num 的初始值是字符串 ‘0’ ,组件挂载时 useMemo 会执行一次 fibonacci(0) 计算并返回 0 。如果后续通过文本框输入的方式修改 num 的值,如 ‘40’ , ‘40’ 与上次的 ‘0’ 不同,则 useMemo 再次计算 fibonacci(40) ,返回 102334155 ,如果后续其他 state 发生了改变,但 num 的值保持 ‘40’ 不变,则 useMemo 不会执行工厂函数,直接返回缓存中的 102334155 ,减少了组件性能损耗
useCallback
然后是 useCallback ,它会把作为第一个参数的回调函数返回给组件,只要第二个参数依赖值数组的依赖项不改变,它就会保证一直返回同一个回调函数(引用),而不是新建一个函数,这也保证了回调函数的闭包也是不变的;相反,当依赖项改变时, useCallback 才会更新回调函数及其闭包
const memoizedFunc = useCallback(() => {/*省略*/}, [a, b]);
// ------------ --------------- -----
// ^ ^ ^
// | | |
// 记忆化的回调函数 回调函数 依赖值数组
其实 useCallback 是 useMemo 的一个马甲,相当
const memoizedFunc = useMemo(() => () => {/*省略*/}, [a, b]);
// ------------ --------------------- -----
// ^ ^ --------------- ^
// | | ^ |
// 工厂函数返回的回调函数 工厂函数 回调函数 依赖值数组