React?中?memo?useMemo?useCallback?到底該怎么用
React.memo怎么用
React.memo()
是一個(gè)高階組件 (HOC),它接收一個(gè)組件A作為參數(shù)并返回一個(gè)組件B,如果組件B的 props(或其中的值)沒有改變,則組件 B 會(huì)阻止組件 A 重新渲染 。
下面我們看一個(gè)示例:
const ParentComponent = () => { const [ count, setCount ] = useState(0); const handleParent = () => { console.log('clicked ParentComponent'); setCount(preCount => preCount + 1); }; return ( <div> <div onClick={handleParent}>父組件,點(diǎn)擊了{(lán)count}次</div> <ChildrenComponent /> </div> ); }; const ChildrenComponent = () => { console.log('ChildrenComponent rending'); return <div>我是子組件</div>; };
點(diǎn)擊父組件:
可以看到控制臺(tái)中輸出了子組件里的打印,表示子組件 rerender 了,如果子組件中有龐大的 dom 結(jié)構(gòu)和計(jì)算,那是非常消耗性能的事,通過 memo 我們可以對(duì)比 render 前后的 prop 變化,如果沒有變化就不會(huì)重新 render 子組件:
const ChildrenComponent = memo(() => { console.log('ChildrenComponent rending'); return <div>我是子組件</div>; });
把子組件通過 memo 包裹后就不會(huì)因?yàn)楦附M件更新導(dǎo)致的 render 了
React.useMemo怎么用
React.memo()
是一個(gè) HOC,而 useMemo() 是一個(gè) React Hook。 使用 useMemo()
,我們可以返回記憶值來避免函數(shù)的依賴項(xiàng)沒有改變的情況下重新渲染。并且可以避免在每次渲染時(shí)都進(jìn)行高開銷的計(jì)算的優(yōu)化的策略。
const sum = ()=>{ return a+b } const result = useMemo(()=>{sum()},[a,b]) // 只有在a或者b的值變化時(shí)才會(huì)觸發(fā)sum函數(shù)執(zhí)行
React.memo()和useMemo()的主要區(qū)別
從上面的例子中,我們可以看到 React.memo()
和 useMemo()
之間的主要區(qū)別:
React.memo()
是一個(gè)高階組件,我們可以使用它來包裝我們不想重新渲染的組件,除非其中的 props 發(fā)生變化useMemo()
是一個(gè) React Hook,我們可以使用它在組件中包裝函數(shù)。 我們可以使用它來確保該函數(shù)中的值僅在其依賴項(xiàng)之一發(fā)生變化時(shí)才重新計(jì)算
雖然 memoization 似乎是一個(gè)可以隨處使用的巧妙小技巧,但只有在絕對(duì)需要這些性能提升時(shí)才應(yīng)該使用它。 Memoization 會(huì)占用運(yùn)行它的機(jī)器上的內(nèi)存空間,因此可能會(huì)導(dǎo)致意想不到的效果。
React.useCallback怎么用
我們看一下下面這個(gè)示例:
const ParentComponent = () => { const [ count, setCount ] = useState(0); const [ childCount, setChildCount ] = useState(0) const handleChildren = () => { console.log('clicked ChildrenComponent'); setChildCount(preCount => preCount + 1) }; const handleParent = () => { console.log('clicked ParentComponent'); setCount(preCount => preCount + 1); }; return ( <div> <div onClick={handleParent}>父組件,點(diǎn)擊了{(lán)count}次</div> <ChildrenComponent handleChildren={handleChildren} data={childCount}/> </div> ); }; const ChildrenComponent = memo(({ handleChildren, data }) => { console.log('ChildrenComponent rending', data); return <div onClick={handleChildren}>ChildrenComponent,子組件被點(diǎn)擊了{(lán)data}次 </div>; });
在上面的例子中,我們把子組件通過 React.memo 包起來了,希望在父組件更新的時(shí)候,子組件不會(huì) 再次render,那么會(huì)和我們想的一樣嗎?
當(dāng)點(diǎn)擊父組件時(shí),子組件再次 render 了, 因?yàn)樽咏M件的 prop 傳入了有函數(shù) handleChildren ,當(dāng)點(diǎn)擊父組件時(shí)更改了 state 值導(dǎo)致父組件重新 render,那么原來的 hanldeChildren 函數(shù)和更新后的 hanldeChildren 顯然處在不同的執(zhí)行環(huán)境中,他們并不是一個(gè)函數(shù),在內(nèi)存中不是同一個(gè)引用地址,所以就導(dǎo)致了 memo 的包裹無效,因?yàn)?prop 改變了。
useCallback 需要傳入兩個(gè)參數(shù)
- callback(僅僅是個(gè)函數(shù)),把要做事情的函數(shù)放在callback函數(shù)體內(nèi)執(zhí)行
- deps 要做事情的函數(shù)需要引入的外部參數(shù)或者是依賴參數(shù)
const handleChildrenCallback = useCallback(() => { handleChildren(); }, []);// 咱們不需要就不要傳入
useCallback 返回一個(gè) memoized 回調(diào)函數(shù)。在依賴參數(shù)不變的情況下,返回的回調(diào)函數(shù)是同一個(gè)引用地址
注意 每當(dāng)依賴參數(shù)發(fā)生改變useCallback就會(huì)自動(dòng)重新返回一個(gè)新的 memoized 函數(shù)(地址發(fā)生改變)
上面就是沒有使用 useCallBack 的使用場(chǎng)景,現(xiàn)在我們知道了,把要傳遞的函數(shù)參數(shù)通過 useCallBack 包裹一層,這樣返回的回調(diào)函數(shù)就是同一個(gè)引用地址,這樣子組件就不會(huì) rerender 了:
const handleChildren = useCallback(() => { console.log('clicked ChildrenComponent'); setChildCount(preCount => preCount + 1) }, [setChildCount]);
現(xiàn)在在點(diǎn)擊父組件后,子組件就不會(huì)再 rerender 了。
大伙現(xiàn)在應(yīng)該明白了useCallback的作用了,它主要用來配合memo用于優(yōu)化子組件的渲染次數(shù)
memo與useMemo及useCallback的區(qū)別
- memo用來優(yōu)化函數(shù)組件的重復(fù)渲染行為,針對(duì)的是一個(gè)組件
- useMemo返回一個(gè)memoized的值
- 本質(zhì)都是用同樣的算法來判定依賴是否發(fā)生改變,繼而決定是否觸發(fā)memo或者useMemo中的邏輯,利用memo就可以避免不必要的重復(fù)計(jì)算,減少資源浪費(fèi)
- useCallback返回一個(gè)memoized的函數(shù)
防止不必要的 effect
如果一個(gè)值被 useEffect 依賴,那它可能需要被緩存,這樣可以避免重復(fù)執(zhí)行 effect。
const Component = () => { // 在 re-renders 之間緩存 a 的引用 const a = useMemo(() => ({ test: 1 }), []); useEffect(() => { // 只有當(dāng) a 的值變化時(shí),這里才會(huì)被觸發(fā) doSomething(); }, [a]); // the rest of the code };
useCallback 同理:
const Component = () => { // 在 re-renders 之間緩存 fetch 函數(shù) const fetch = useCallback(() => { console.log('fetch some data here'); }, []); useEffect(() => { // 僅fetch函數(shù)的值被改變時(shí),這里才會(huì)被觸發(fā) fetch(); }, [fetch]); // the rest of the code };
當(dāng)變量直接或者通過依賴鏈成為 useEffect 的依賴項(xiàng)時(shí),那它可能需要被緩存。這也是 useMemo 和 useCallback 得基本用法之一。
到此這篇關(guān)于React 中 memo useMemo useCallback 到底該怎么用的文章就介紹到這了,更多相關(guān)React memo useMemo useCallback內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React?split實(shí)現(xiàn)分割字符串的使用示例
當(dāng)我們需要將一個(gè)字符串按照指定的分隔符進(jìn)行分割成數(shù)組時(shí),我們可以在組件的生命周期方法中使用split方法來實(shí)現(xiàn)這個(gè)功能,本文就來介紹一下,感興趣的可以了解下2023-10-10解析TypeError:import_react_native.AppState.removeEventListener
這篇文章主要為大家介紹了TypeError:import_react_native.AppState.removeEventListener?is?not?a?function問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09React項(xiàng)目中動(dòng)態(tài)插入HTML內(nèi)容的實(shí)現(xiàn)
本文主要介紹了React項(xiàng)目中動(dòng)態(tài)插入HTML內(nèi)容的實(shí)現(xiàn),通過使用React的dangerouslySetInnerHTML屬性,我們可以將HTML內(nèi)容插入到組件中,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10React事件監(jiān)聽和State狀態(tài)修改方式
這篇文章主要介紹了React事件監(jiān)聽和State狀態(tài)修改方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08關(guān)于React16.0的componentDidCatch方法解讀
這篇文章主要介紹了關(guān)于React16.0的componentDidCatch方法解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05JavaScript React如何修改默認(rèn)端口號(hào)方法詳解
這篇文章主要介紹了JavaScript React如何修改默認(rèn)端口號(hào)方法詳解,文中通過步驟圖片解析介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07基于visual studio code + react 開發(fā)環(huán)境搭建過程
今天通過本文給大家分享基于visual studio code + react 開發(fā)環(huán)境搭建過程,本文給大家介紹的非常詳細(xì),包括react安裝問題及安裝 Debugger for Chrome的方法,需要的朋友跟隨小編一起看看吧2021-07-07Shopee在React?Native?架構(gòu)方面的探索及發(fā)展歷程
這篇文章主要介紹了Shopee在React?Native?架構(gòu)方面的探索,本文會(huì)從發(fā)展歷史、架構(gòu)模型、系統(tǒng)設(shè)計(jì)、遷移方案四個(gè)方向逐一介紹我們?nèi)绾我徊讲降貪M足多團(tuán)隊(duì)在復(fù)雜業(yè)務(wù)中的開發(fā)需求,需要的朋友可以參考下2022-07-07