介紹React.memo, useMemo 和 useCallback


什么是 React.memo ?

React.memo 和 React.PureComponent 類似, React.PureComponent 在類組件中使用,而React.memo 在函數組件中使用

看下面兩個例子,有兩個計數器組件,兩個計數器的數據都來源於父組件,第一個計數器通過點擊按鈕數字會不斷累加而發生改變,第二個計數器沒有按鈕控制數字改變。

const App = () => { const [count1, setCount1] = React.useState(0) const [count2, setCount2] = React.useState(0) const increaseCounter1 = () => { setCount1(count1 => count1 + 1) } return ( <> <button onClick={increaseCounter1}>Increase counter 1</button> <Counter value={count1}>Counter 1</Counter> <Counter value={count2}>Coutner 2</Counter> </> ) } 

計數器組件

const Counter = ({value, children}) => { console.log('Render: ', children) return ( <div> {children}: {value} </div> ) } export default Counter 

但是不管這個兩個計算器的數據是否發生改變,Counter 組件都會輸出 Render 來。現在我們嘗試使用 React.memo 包裹這個組件。

const Counter = ({value, children}) => { console.log('Render: ', children) return ( <div> {children}: {value} </div> ) } export default React.memo(Counter) 

React.memo 淺層對比 prop 和 state 的方式來實現了該函數。現在開始第二個計數器將不會重新渲染了,由於 prop 沒有發生改變。

在 React 應用中,當某個組件的狀態發生變化時,它會以該組件為根,重新渲染整個組件子樹。

如要避免不必要的子組件的重渲染,你需要在所有可能的地方使用 PureComponent,或是手動實現 shouldComponentUpdate 方法。

useMemo and useCallback

useMemo 相當於Vue中computed里的計算屬性,當某個依賴項改變時才重新計算值,這種優化有助於避免在每次渲染時都進行高開銷的計算。

React.useMemo(() => { fooFunction() }, [dependencies]) 
React.useCallback(() => { fooFunction() }, [dependencies]) 

useCallback(fn, deps) 相當於 useMemo(() => fn, deps)。

useCallback 和 useMemo 參數相同,第一個參數是函數,第二個參數是依賴項的數組。主要區別是 React.useMemo 將調用 fn 函數並返回其結果,而 React.useCallback 將返回 fn 函數而不調用它。

看看下來例子

const App = () => { const fooFunction = () => { return 'Foo is just Food without D' } const useMemoResult = React.useMemo(fooFunction, []) const useCallbackResult = React.useCallback(fooFunction, []) console.log('useMemoResult: ', useMemoResult) console.log('useCallbackResult: ', useCallbackResult) return <p>Foo is just food without D</p> } 

最后得到的輸出結果
在這里插入圖片描述

const Me = ({girlFriendWords}) => { // Provided that girlFriendWords is a string const myReply = decideWhatToSay (girlFriendWords) return <p>{myReply}</p> } 

代碼中計算 myReply 值,默認每次組件渲染的時候都會重新執行

const Me = ({girlFriendWords}) => { // Provided that girlFriendWords is a string const myReply = React.useMemo(() => decideWhatToSay (girlFriendWords), [girlFriendWords]) return <p>{myReply}</p> } 

使用 React.useMemo 通過 [girlFriendWords] 作為依賴項,當依賴的值發生改變,函數才會重新執行 decideWhatToSay

useCallback

使用場景是:有一個父組件,其中包含子組件,子組件接收一個函數作為props;通常而言,如果父組件更新了,子組件也會執行更新;

import React, { useMemo, useCallback } from "react" let Counter = ({ value, children, onClick }) => { console.log('Render: ', children) return ( <div onClick={onClick}> {children}: {value} </div> ) } Counter = React.memo(Counter) const App = () => { const [count1, setCount1] = React.useState(0) const [count2, setCount2] = React.useState(0) const increaseCounter1 = () => { setCount1(count1 => count1 + 1) } const increaseCounter2 = () => { setCount2(count2 => count2 + 1) } return ( <> <Counter value={count1} onClick={increaseCounter1}>Counter 1</Counter> <Counter value={count2} onClick={increaseCounter2}>Coutner 2</Counter> </> ) } export default App 

但是大多數場景下,更新是沒有必要的,我們可以借助useCallback來返回函數,然后把這個函數作為props傳遞給子組件;這樣,子組件就能避免不必要的更新。

import React, { useMemo, useCallback } from "react" let Counter = ({ value, children, onClick }) => { console.log('Render: ', children) return ( <div onClick={onClick}> {children}: {value} </div> ) } Counter = React.memo(Counter) const App = () => { const [count1, setCount1] = React.useState(0) const [count2, setCount2] = React.useState(0) const increaseCounter1 = useCallback(() => { setCount1(count1 => count1 + 1) }, []) const increaseCounter2 = useCallback(() => { setCount2(count2 => count2 + 1) }, []) console.log(increaseCounter1) return ( <> <Counter value={count1} onClick={increaseCounter1}>Counter 1</Counter> <Counter value={count2} onClick={increaseCounter2}>Coutner 2</Counter> </> ) } export default App


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM