useEffect, useCallback, useMemo三者有何區(qū)別?

原文:https://segmentfault.com/a/1190000039657107
關(guān)注公眾號 前端人,回復(fù)“加群”
添加無廣告優(yōu)質(zhì)學(xué)習(xí)群
背景
在目前的react開發(fā)中,很多新項(xiàng)目都采用函數(shù)組件,因此,我們免不了會接觸到hooks。此外,Hooks也是前端面試中react方面的一個高頻考點(diǎn),需要掌握常用的幾種hooks。
常用的有
基本:useState, useEffect, useContext 額外:useCallback, useMemo, useRef
剛接觸公司的react項(xiàng)目代碼時,發(fā)現(xiàn)組件都是用的函數(shù)組件,不得不去學(xué)習(xí)hooks,之前只會類組件和react基礎(chǔ)
其中useState不用說了,很容易理解,使我們在函數(shù)組件中也能像類組件那樣獲取、改變state
項(xiàng)目中很多地方都有useEffect, useCallback, useMemo,初看時感覺這三個都是包著一個東西,有它們跟沒有它們感覺也沒什么區(qū)別,很難分清這三個什么時候要用
所以這里就略微總結(jié)一下,附上一點(diǎn)個人在開發(fā)過程中的理解。
其實(shí)這三個區(qū)別還是挺明顯的:
useEffect
useEffect可以幫助我們在DOM更新完成后執(zhí)行某些副作用操作,如數(shù)據(jù)獲取,設(shè)置訂閱以及手動更改 React 組件中的 DOM 等
有了useEffect,我們可以在函數(shù)組件中實(shí)現(xiàn) 像類組件中的生命周期那樣某個階段做某件事情,具有:
componentDidMount componentDidUpdate componentWillUnmount
基本用法
useEffect(() => {
console.log('這是一個不含依賴數(shù)組的useEffect,每次render都會執(zhí)行!')
})
useEffect 規(guī)則
沒有傳第二個參數(shù)時,在每次 render 之后都會執(zhí)行 useEffect中的內(nèi)容 useEffect接受第二個參數(shù)來控制跳過執(zhí)行,下次 render 后如果指定的值沒有變化就不會執(zhí)行 useEffect 是在 render 之后瀏覽器已經(jīng)渲染結(jié)束才執(zhí)行 useEffect 的第二個參數(shù)是可選的,類型是一個數(shù)組 根據(jù)第二個參數(shù)的不同情況,useEffect具有不同作用
1. 空數(shù)組
useEffect 只在第一次渲染時執(zhí)行,由于空數(shù)組中沒有值,始終沒有改變,所以后續(xù)render不執(zhí)行,相當(dāng)于生命周期中的componentDidMount
useEffect(() => {
console.log('只在第一次渲染時執(zhí)行') }, []
);
2. 非空數(shù)組
無論數(shù)組中有幾個元素,數(shù)組中只要有任意一項(xiàng)發(fā)生了改變,useEffect 都會調(diào)用
useEffect(() => {
getStuInfo({ id: stuId }); }, [getStuInfo, stuId]
);
getStuInfo或者stuId改變時調(diào)用getStuInfo函數(shù)
useCallback 和 useMemo
相同點(diǎn):
useCallback 和 useMemo 都是性能優(yōu)化的手段,類似于類組件中的 shouldComponentUpdate,在子組件中使用 shouldComponentUpdate, 判定該組件的 props 和 state 是否有變化,從而避免每次父組件render時都去重新渲染子組件。
區(qū)別:
useCallback 和 useMemo 的區(qū)別是useCallback返回一個函數(shù),當(dāng)把它返回的這個函數(shù)作為子組件使用時,可以避免每次父組件更新時都重新渲染這個子組件,
const renderButton = useCallback(
() => (
<Button type="link">
{buttonText}
</Button>
),
[buttonText] // 當(dāng)buttonText改變時才重新渲染renderButton
);
useMemo返回的的是一個值,用于避免在每次渲染時都進(jìn)行高開銷的計(jì)算。例:
// 僅當(dāng)num改變時才重新計(jì)算結(jié)果
const result = useMemo(() => {
for (let i = 0; i < 100000; i++) {
(num * Math.pow(2, 15)) / 9;
}
}, [num]);
補(bǔ)充:
什么時候用useCallback和useMemo進(jìn)行優(yōu)化
任何的優(yōu)化都是有代價的,useCallback和useMemo雖然能夠避免非必要渲染,但為此也付出了成本,比如保留額外的依賴數(shù)組;保留舊值的副本,以便在與先前依賴相同的情況下返回……
考慮到這些,在我們的項(xiàng)目中什么時候用useCallback和useMemo進(jìn)行優(yōu)化呢?
目前所在的公司,項(xiàng)目中所有地方都用了useCallback和useMemo,就這塊問了一下mentor,他給出的答復(fù)是這樣的:
就算有比對代價也比較小,因?yàn)槟呐率菍ο笠仓皇且帽容^。
我覺得任何時候都用是一個好的習(xí)慣,但是大部分時間不用也沒什么大問題。但是如果該函數(shù)或變量作為 props 傳給子組件,請一定要用,避免子組件的非必要渲染
然后要記得 React 的工作方式遵循純函數(shù),特別是數(shù)據(jù)的 immutable,因此,使用 memo 很重要。
但大部分時候都不足以成為性能瓶頸
回復(fù) 資料包領(lǐng)取我整理的進(jìn)階資料包回復(fù) 加群,加入前端進(jìn)階群console.log("文章點(diǎn)贊===文章點(diǎn)在看===你我都快樂")Bug離我更遠(yuǎn)了,下班離我更近了

