如何使用
感覺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
綜上:
- useCallback(callback, deps) 相當於useMemo(() => fn, deps);
- deps依賴項數組發生改變時,纔會引起useCallbak和useMemo的返回值的更新
- 不傳deps時,組件每次渲染他們都會重新計算;
- 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;
}