首頁 > 軟體

React.memo 和 useMemo 的使用問題小結

2022-11-05 14:00:43

問題背景

大家在使用 React 框架進行開發時一定遇到過以下問題:

  • 當函數式元件中的某一狀態改變,整個元件重新整理,重新渲染
  • 在類元件中 setState() 時,整個元件也會重新渲染
  • 以上問題若不進行優化,導致的結果是:
  • 隨著程式碼的增加,每次的狀態改變,頁面進行一次 reRender ,這將產生很多不必要的 reRender 不僅浪費效能,從而導致頁面卡頓;

useMemo 進行優化

以下面 App 元件進行分析

import './App.css';
import ProfileTest from './components';
import { Profiler, useEffect, useMemo, useState, useRef } from 'react'
function App () {
  const [name, setName] = useState('')
  const [num, setNum] = useState(0)
  useEffect(() => {
    setTimeout(() => {
      console.log('111')
      setName('xxx')
    }, 2000)
  }, [])
  const memoVal = useMemo(() => {
    console.log('執行了useMemo num值為:', num);
    return num + 1
  }, [num])
  console.log('memoVal值為:', memoVal)
  console.log('父元件執行分割線----------------------------------------------------')
  const changeNum = () => {
    setNum(2)
  }
  return (
    <Profiler id='profile-test'>
      <div className="App">
        {/* <ProfileTest /> */}
        <button style={{ marginTop: 100 }} onClick={changeNum}>改變num</button>
      </div>
    </Profiler>
  );
}
export default App;

以上元件在首次渲染、以及 2秒後的執行結構如下圖所示:

很顯然首次渲染執行了,useMemo,而2秒後有狀態變化後沒有執行useMemo。
點選按鈕改變 useMemo 的依賴項後可以發現,如下圖所示 useMemo 又執行了。

因此在使用函數式元件時,可以使用 useMemo 減少不必要的reRender 提高元件的效能;

React.memo 進行優化

在以上元件的基礎上,給App 增加一個子元件,程式碼如下所示:

import React from 'react'

export default function Children(props) {
  console.log('子元件執行了,接收的props是', props)
  console.log('子元件渲染分割線------------------------------------------')
  return <div>子元件</div>
}

首次render 以及 2s後元件的 reRender 控制檯列印結果如下圖所示:

由上圖可以看出,reRender 時Children 元件的props並未變化,因此,此次Children 元件的reRender 是不必要的,需要進行優化;

props的值是基本型別

如果 Children 的 props 是基本型別,則可以做一下優化:

import React, { memo } from 'react'

function Children(props) {
  console.log('子元件執行了,接收的props是', props)
  console.log('子元件渲染分割線------------------------------------------')
  return <div>子元件</div>
}
export default memo(Children)

優化後控制檯列印如下資訊,一下資訊可以看出 Children 元件沒有進行 reRender

props的值是參照型別

若子元件的 props 是參照型別 ,則需要進行深度比較,此時React.memo()要傳入第二個引數進行深度比較,改變後 Children 元件的程式碼如下所示:

import React, { memo } from 'react'

function Children(props) {
  console.log('子元件執行了,接收的props是', props)
  console.log('子元件渲染分割線------------------------------------------')
  return <div>子元件</div>
}
export default memo(Children, (preProps, nextProps) => {
  return JSON.stringify(preProps) === JSON.stringify(nextProps)
})

以上 memo 第二個引數 ,通過比較 preProps 和 nextProps 返回一個布林值,使得props 進行深度比較;
注意:React.memo的第二個引數進行深度比較時有一定開銷,其產生的開銷存在大於子元件reRender的可能

寫在最後

useMemo() 和 React.memo() 都是進行元件效能優化的方式,其區別是

  • useMemo 可以進行更加細粒度的優化(有依賴項)
  • React.memo() 可以控制props的淺比較和深度比較
  • React.memo在沒有第二個引數的時候相當於class中的PureComponent,當增加了第二個引數的時候相當於生命週期中的shouldComponentUpdate;

到此這篇關於React.memo 和 useMemo 的使用問題小結的文章就介紹到這了,更多相關React.memo 和 useMemo內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com