React手冊(cè) Hooks 之 useCallback
描述
????React?官網(wǎng)對(duì)?
u
seCallback
?
的描述原文
u
seCallback
?is a?React Hook?that lets you cache a function definition between re-renders.
useCallback?
是一個(gè) React Hook,可以在你重新渲染之間緩存函數(shù)的定義.
????當(dāng)你在渲染一個(gè)函數(shù)組件的時(shí)候, 如果在組件內(nèi)部又聲明了函數(shù), 那么使用?
u
seCallback?
來(lái)包裝這個(gè)內(nèi)部函數(shù)可以緩存該函數(shù)引用, 避免每次重新渲染都獲取到新函數(shù).
?場(chǎng)景
? ? React: 默認(rèn)情況下,當(dāng)一個(gè)組件重新渲染時(shí),React 會(huì)遞歸地重新渲染它的所有子組件
? 因此當(dāng)父組件狀態(tài)變化時(shí), 很多時(shí)候大部分子組件都是不必重新渲染的,?React.memo?就是專門解決這種問題的一個(gè)方法, 被?React.memo?包裝后的組件, 每次渲染會(huì)對(duì)所有?props?淺對(duì)比, 如果沒有變化, 則不進(jìn)行重新渲染, 從而提升性能,?但是如果傳遞的?props?是一個(gè)函數(shù),?且這個(gè)函數(shù)還是在父組件內(nèi)部創(chuàng)建的, 那么父組件每次渲染時(shí)給子組件傳遞的函數(shù)都是一個(gè)新的函數(shù)引用, 這時(shí)?React.memo?會(huì)認(rèn)為?props?發(fā)生變化并重新渲染,?起不到優(yōu)化的作用.
??
u
seCallback
?
就是為了解決這個(gè)?React.memo?優(yōu)化失效的問題,?它會(huì)在父組件外部緩存函數(shù), 當(dāng)父組件渲染時(shí), 會(huì)返回函數(shù)的緩存, 讓?React.memo?能拿到相同的函數(shù)引用, 從而讓優(yōu)化生效.
? ??在類組件中,?因?yàn)?/span>可以通過(guò)?this?來(lái)獲取同一個(gè)方法引用來(lái)避免這個(gè)問題.
????
????接口定義:
參數(shù)
fn: Function
? 需要緩存的函數(shù),?React?并不會(huì)調(diào)用它, 通常情況下是一個(gè)需要傳遞給子組件的函數(shù), 緩存的意義也是為了避免子組件不必要的渲染.
dependencies: Array<mixed>
? 緩存函數(shù)?fn?的時(shí)候, 需要告訴?
u
seCallback?
何時(shí)更新緩存,
?
dependencies?
里的狀態(tài)發(fā)生變化的時(shí)候, 就會(huì)使緩存的函數(shù)進(jìn)行更新
?當(dāng)沒有傳,
?dependencies?
的時(shí)候,
?
u
seCallback?
始終返回一個(gè)新函數(shù), 這樣也會(huì)讓
?React.memo?
的優(yōu)化失效, 所以一定要傳, 當(dāng)傳入的是一個(gè)空數(shù)組的時(shí)候,?因為依賴項(xiàng)始終是空,?檢測(cè)不到變化,?所以渲染之后緩存無(wú)法再更新.
返回
? ??返回一個(gè)函數(shù)引用, 如果?dependencies?
沒有發(fā)生變化, 那么拿到的就是緩存中的函數(shù)引用, 反之會(huì)拿到一個(gè)新的函數(shù)引用.
用法1
????配合
?React.memo
對(duì)子組件的渲染做優(yōu)化,?沒有使用
?
React.memo
和
?
u
seCallback
的情況下, 兩個(gè)子組件任意一個(gè)點(diǎn)擊, 都會(huì)使整個(gè)
MyApp
組件和所有子組件重新渲染, 增加了優(yōu)化之后, 每次點(diǎn)擊
?MemoMyButton
都只會(huì)讓
?MyApp
和當(dāng)前點(diǎn)擊的子組件重新渲染.
用法2
????當(dāng)傳入?dependencies
后, 依賴的變化必然會(huì)導(dǎo)致函數(shù)緩存的更新, 有時(shí)這是不必要的, 也就是需要一種可以更新狀態(tài), 但不用更新函數(shù)緩存的方法,?
u
seCallback
同樣具有這樣的效果.
? ??
在這個(gè)例子中, count?的變化, 始終會(huì)讓?countClick?更新,?這同樣會(huì)讓?React.memo 失效, 顯然?count 并不是一個(gè)合適的依賴項(xiàng), 但是不傳的話又會(huì)導(dǎo)致函數(shù)始終使用緩存中的狀態(tài),?count?就會(huì)一直等于 1, 這種情況我們需要使用下面的寫法.
????
這樣的寫法可以讓
?
u
seCallback
始終返回緩存中的函數(shù), 同時(shí)也可以正確更新
count
的狀態(tài).
用法3
????u
seCallback
還可以配合?useEffect 使用,當(dāng) useEffect 的依賴是一個(gè)函數(shù)時(shí),可以使用?
u
seCallback
來(lái)緩存依賴函數(shù),來(lái)避免
useEffect
不必要的執(zhí)行
??不過(guò)這種方式并不推薦使用,一個(gè)函數(shù)的依賴項(xiàng)會(huì)很奇怪,而且完全可以不使用?
u
seCallback?
達(dá)到效果,像下面這樣改寫:
總結(jié)
u
seCallback?
是協(xié)助?
React.memo?
對(duì)子組件渲染優(yōu)化的一個(gè)
?hook;
u
seCallback
需要謹(jǐn)慎使用, 傳入合適的
?
dependencies
是優(yōu)化的關(guān)鍵;
u
seCallback
不應(yīng)該用做功能, 只用來(lái)做優(yōu)化;
不要在循環(huán)中直接使用
?u
seCallback,
必要的話就寫在循環(huán)的子組件中;
可以和?
u
seEffect
一起使用,但是并不推薦;
dependencies
不傳會(huì)始終返回新函數(shù), 傳空數(shù)組會(huì)在渲染一次之后一直緩存;