useCallback和useMemo源码分析
欢迎关注前端早茶,与广东靓仔携手共同进阶
前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~
公众号作者:广东靓仔
使用
感觉useCallback和useMemo两者很像,前者返回一个memorized的回调函数,后者返回一个memorized的值。
看一下他们是如何定义的
useCallback接受一个回调函数和依赖项数组作为参数,返回回调函数的memorized版本
// useCallback useCallback<T>(callback: T, deps: Array<mixed> | void | null): T
当这个回调函数传递给自组件时,可以用useCallback避免自组件非必要的渲染
useMemo接受创建函数和依赖项数组作为参数,会在依赖项发生改变时重新计算memorized值
// useMemo
// 创建函数是有返回值的,这是跟useCallback不同的地方
useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T
要避免每次渲染都进行高开销的计算时可以用useMemo
小结
1、useCallback(callback, deps) 相当于useMemo(() => fn, deps);
2、deps依赖项数组发生改变时,才会引起useCallbak和useMemo的返回值的更新
3、不传deps时,组件每次渲染他们都会重新计算;
4、deps传空数组[]时,只有组件首次加载会计算;
源码分析
首次挂载组件时,走的时mount**, 组件更新时走的是update**
useCallback和useMemo的源码部分比较相似和简单。
// mount阶段就是获取到传入的回调函数和依赖数组,保存到hook的memorizedState中,然后返回回调函数。
function mountCallback<T>(callback: T, deps: Array<mixed> | void | null): T { const hook = mountWorkInProgressHook(); const nextDeps = deps === undefined ? null : deps; hook.memoizedState = [callback, nextDeps]; return callback; }
// update阶段
function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T { const hook = updateWorkInProgressHook(); // 从hook的memorizedState中获取上次保存的值[callback, deps], const nextDeps = deps === undefined ? null : deps; const prevState = hook.memoizedState; if (prevState !== null) { if (nextDeps !== null) { const prevDeps: Array<mixed> | null = prevState[1]; // 比较新的deps和之前的deps是否相等 if (areHookInputsEqual(nextDeps, prevDeps)) { // 如果相等,返回memorized的callback return prevState[0]; } } } // 如果deps发生变化,更新hook的memorizedState,并返回最新的callback hook.memoizedState = [callback, nextDeps]; return callback; }
useMemo的源码
// mount阶段, 执行创建函数获得返回值 // 保存到hook的memorizedState中[nextValue, nextDeps] function mountMemo<T>( nextCreate: () => T, deps: Array<mixed> | void | null, ): T { const hook = mountWorkInProgressHook(); const nextDeps = deps === undefined ? null : deps; const nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; }
// update阶段
function updateMemo<T>( nextCreate: () => T, deps: Array<mixed> | void | null, ): T { const hook = updateWorkInProgressHook(); // 获取新的deps const nextDeps = deps === undefined ? null : deps; // 从memorizedState中获得上次保存的值 const prevState = hook.memoizedState; if (prevState !== null) { if (nextDeps !== null) { // 比较新deps和旧deps是否相等,如果两者相等,返回旧的创建函数的返回值 const prevDeps: Array<mixed> | null = prevState[1]; if (areHookInputsEqual(nextDeps, prevDeps)) { return prevState[0]; } } } // 如果deps发生改变,hook中保存新的返回值和deps,并返回新的创建函数的返回值 const nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; }
两者从源码看,还是很相似的
欢迎关注前端早茶,与广东靓仔携手共同进阶
前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~
公众号作者:广东靓仔