useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
把“創(chuàng)建”函數(shù)和依賴項(xiàng)數(shù)組作為參數(shù)傳入 useMemo,它僅會(huì)在某個(gè)依賴項(xiàng)改變時(shí)才重新計(jì)算 memoized 值。這種優(yōu)化有助于避免在每次渲染時(shí)都進(jìn)行高開銷的計(jì)算泽示。
也就是說useMemo可以讓函數(shù)在某個(gè)依賴項(xiàng)改變的時(shí)候才運(yùn)行铐刘,這可以避免很多不必要的開銷焊切。舉個(gè)例子:
不使用useMemo
function Example() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
function getNum() {
return Array.from({length: count * 100}, (v, i) => i).reduce((a, b) => a+b)
}
return <div>
<h4>總和:{getNum()}</h4>
<div>
<button onClick={() => setCount(count + 1)}>+1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
}
上面這個(gè)組件祸轮,維護(hù)了兩個(gè)state,可以看到getNum
的計(jì)算僅僅跟count
有關(guān)哀峻,但是現(xiàn)在無論是count
還是val
變化涡相,都會(huì)導(dǎo)致getNum
重新計(jì)算,所以這里我們希望val
修改的時(shí)候剩蟀,不需要再次計(jì)算催蝗,這種情況下我們可以使用useMemo
。
使用useMemo
function Example() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
const getNum = useMemo(() => {
return Array.from({length: count * 100}, (v, i) => i).reduce((a, b) => a+b)
}, [count])
return <div>
<h4>總和:{getNum}</h4>
<div>
<button onClick={() => setCount(count + 1)}>+1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
}
使用useMemo
后育特,并將count
作為依賴值傳遞進(jìn)去丙号,此時(shí)僅當(dāng)count
變化時(shí)才會(huì)重新執(zhí)行getNum
。
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
把內(nèi)聯(lián)回調(diào)函數(shù)及依賴項(xiàng)數(shù)組作為參數(shù)傳入 useCallback且预,它將返回該回調(diào)函數(shù)的 memoized 版本槽袄,該回調(diào)函數(shù)僅在某個(gè)依賴項(xiàng)改變時(shí)才會(huì)更新。當(dāng)你把回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子組件時(shí)锋谐,它將非常有用遍尺。
看起來似乎和useMemo差不多,我們來看看這兩者有什么異同:
useMemo
和useCallback
接收的參數(shù)都是一樣涮拗,都是在其依賴項(xiàng)發(fā)生變化后才執(zhí)行乾戏,都是返回緩存的值,區(qū)別在于useMemo
返回的是函數(shù)運(yùn)行的結(jié)果三热,useCallback
返回的是函數(shù)鼓择。
useCallback(fn, deps) 相當(dāng)于 useMemo(() => fn, deps)
使用場景
正如上面所說的,當(dāng)你把回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子組件時(shí)就漾,它將非常有用呐能。也就是說父組件傳遞一個(gè)函數(shù)給子組件的時(shí)候,由于父組件的更新會(huì)導(dǎo)致該函數(shù)重新生成從而傳遞給子組件的函數(shù)引用發(fā)生了變化抑堡,這就會(huì)導(dǎo)致子組件也會(huì)更新摆出,而很多時(shí)候子組件的更新是沒必要的,所以我們可以通過useCallback
來緩存該函數(shù)首妖,然后傳遞給子組件偎漫。舉個(gè)例子:
function Parent() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
const getNum = useCallback(() => {
return Array.from({length: count * 100}, (v, i) => i).reduce((a, b) => a+b)
}, [count])
return <div>
<Child getNum={getNum} />
<div>
<button onClick={() => setCount(count + 1)}>+1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
}
const Child = React.memo(function ({ getNum }: any) {
return <h4>總和:{getNum()}</h4>
})
使用useCallback
之后,僅當(dāng)count
發(fā)生變化時(shí)Child
組件才會(huì)重新渲染有缆,而val
變化時(shí)象踊,Child
組件是不會(huì)重新渲染的温亲。