React總結2:useMemo 與 useCallback 得使用,元件優化方案
阿新 • • 發佈:2021-10-22
前面
先了解一下在react中的class類元件中的效能優化方面,主要集中於一下兩點
1.呼叫setState時,就會觸發元件重新渲染,無論前後state是否改變
2.父元件更新,子元件也會自動更新
解決方案:
1.使用 immutable 進行比較,在不相等的時候呼叫 setState
2.在shouldComponentUpdate 中判斷前後的資料(prop,state)是否一致,如果沒有變化就返回 false 來阻止更新。
3.使用 pureComponent 代替 component,pureComponent 自帶通過 props 和 state 的淺對比來實現 shouldComponentUpdate()
pureComponent 缺點:可能會因深層的資料不一致而產生錯誤的否定判斷,
從而 shouldComponentUpdate 的結果返回 false,介面得不到更新
下面說下 hooks 中的函式式元件如何優化元件效能方案:
在函式式元件中失去了 shouldComponentUpdate ,我發通過判斷前後狀態來決定是否更新。
在函式式元件中,react 不再區分 mount 和 update 兩個狀態,也就是說函式元件的每一次呼叫都會執行其內部的所有略記,會帶來較大的效能損耗。在此,hooks 中出現了兩個鉤子 useMemo 和 useCallback 來解決函式式元件的效能方案。
先看下 useMemo 和 useCallback 的原始碼
function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;引數形式和 useEffect 一致,useEffect 作用是用於處理副作用,這兩個則不行。 useMemo 和 useCallback 都會在元件第一次渲染的時候執行,之後會在依賴改變時再次執行; 都返回快取的值,useMemo 返回快取的變數,useCallback 返回快取的函式。 先說下 useMemofunction useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;
function Test() { const [count, setCount]下面說下 useCallback 為什麼使用 useCallback,以及 useCallback 所能帶來的效能提升 和 useMemo 類似,當回撥函式床底給經過優化的並使用引用相等性去避免非必要渲染的子元件時,他非常有用,和 pureComponent 的作用相同。就是說父元件傳遞一個函式給子元件的時候,由於父元件的更新會導致該函式重新生成從而傳遞給子元件的函式引用發生了變化,這就會導致子元件也會更新, 很多情況下子元件的更新並不是必要的,所以通過 useCallback 來快取傳遞給子元件的函式。 程式碼示例= useState(1); const [val, setVal] = useState(''); // sum1 每次在 count 與 val 有一個改變的時候都會重新整理元件重新執行 sum1。 // 但是這裡的計算 sum1 只依賴於 count 的值,在 val 修改的時候沒有必要進行 sum1 的計算。 // 這種情況下,我們就可以使用 useMemo,只在count 的值修改時執行計算(sum2) const sum1 = () => { console.log('sum1111'); let sum = 0; for (let i = 0; i < count; i++) { sum += i; } return sum; }; // 每次在 count 的值改變的時候才重新執行計算 const sum2 = useMemo(() => { console.log('sum2222'); let sum = 0; for (let i = 0; i < count; i++) { sum += i; } return sum; }, [count]); return ( <div> <h1>{count}+++{val}+++{sum1()}+++{sum2()}</h1> <div> <button onClick={() => setCount(count + 1)}>+++</button> <input type='text' value={val} onChange={event => setVal(event.target.value)}/> </div> </div> ); }
const Child = ({getNum}) => { return <h1>資料:{getNum}</h1>; }; function Test() { const [count, setCount] = useState(1); const [val, setVal] = useState(''); const sum = useCallback(() => { return Array.from({length: count}, (v, i) => i).reduce((a, b) => a + b); }, [count]); return ( <div> <Child getNum={sum}/> <h1>{count}+++{val}++++{sum()}</h1> <div> <button onClick={() => setCount(count + 1)}>+++</button> <input type='text' value={val} onChange={event => setVal(event.target.value)}/> </div> </div> ); } // 以上只有當 count 改變的時候child元件才會重新渲染