React.memo 和 useMemo 的使用問題小結(jié)
問題背景
大家在使用 React 框架進(jìn)行開發(fā)時一定遇到過以下問題:
- 當(dāng)函數(shù)式組件中的某一狀態(tài)改變,整個組件刷新,重新渲染
- 在類組件中 setState() 時,整個組件也會重新渲染
- 以上問題若不進(jìn)行優(yōu)化,導(dǎo)致的結(jié)果是:
- 隨著代碼的增加,每次的狀態(tài)改變,頁面進(jìn)行一次 reRender ,這將產(chǎn)生很多不必要的 reRender 不僅浪費性能,從而導(dǎo)致頁面卡頓;
useMemo 進(jìn)行優(yōu)化
以下面 App 組件進(jìn)行分析
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秒后的執(zhí)行結(jié)構(gòu)如下圖所示:

很顯然首次渲染執(zhí)行了,useMemo,而2秒后有狀態(tài)變化后沒有執(zhí)行useMemo。
點擊按鈕改變 useMemo 的依賴項后可以發(fā)現(xiàn),如下圖所示 useMemo 又執(zhí)行了。

因此在使用函數(shù)式組件時,可以使用 useMemo 減少不必要的reRender 提高組件的性能;
React.memo 進(jìn)行優(yōu)化
在以上組件的基礎(chǔ)上,給App 增加一個子組件,代碼如下所示:
import React from 'react'
export default function Children(props) {
console.log('子組件運行了,接收的props是', props)
console.log('子組件渲染分割線------------------------------------------')
return <div>子組件</div>
}首次render 以及 2s后組件的 reRender 控制臺打印結(jié)果如下圖所示:

由上圖可以看出,reRender 時Children 組件的props并未變化,因此,此次Children 組件的reRender 是不必要的,需要進(jìn)行優(yōu)化;
props的值是基本類型
如果 Children 的 props 是基本類型,則可以做一下優(yōu)化:
import React, { memo } from 'react'
function Children(props) {
console.log('子組件運行了,接收的props是', props)
console.log('子組件渲染分割線------------------------------------------')
return <div>子組件</div>
}
export default memo(Children)優(yōu)化后控制臺打印如下信息,一下信息可以看出 Children 組件沒有進(jìn)行 reRender

props的值是引用類型
若子組件的 props 是引用類型 ,則需要進(jìn)行深度比較,此時React.memo()要傳入第二個參數(shù)進(jìn)行深度比較,改變后 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 第二個參數(shù) ,通過比較 preProps 和 nextProps 返回一個布爾值,使得props 進(jìn)行深度比較;注意:React.memo的第二個參數(shù)進(jìn)行深度比較時有一定開銷,其產(chǎn)生的開銷存在大于子組件reRender的可能
寫在最后
useMemo() 和 React.memo() 都是進(jìn)行組件性能優(yōu)化的方式,其區(qū)別是
- useMemo 可以進(jìn)行更加細(xì)粒度的優(yōu)化(有依賴項)
- React.memo() 可以控制props的淺比較和深度比較
- React.memo在沒有第二個參數(shù)的時候相當(dāng)于class中的PureComponent,當(dāng)增加了第二個參數(shù)的時候相當(dāng)于生命周期中的shouldComponentUpdate;
到此這篇關(guān)于React.memo 和 useMemo 的使用問題小結(jié)的文章就介紹到這了,更多相關(guān)React.memo 和 useMemo內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解React Native 采用Fetch方式發(fā)送跨域POST請求
這篇文章主要介紹了詳解React Native 采用Fetch方式發(fā)送跨域POST請求,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
40行代碼把Vue3的響應(yīng)式集成進(jìn)React做狀態(tài)管理
這篇文章主要介紹了40行代碼把Vue3的響應(yīng)式集成進(jìn)React做狀態(tài)管理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
React Hooks - useContetx和useReducer的使用實例詳解
這篇文章主要介紹了React Hooks - useContetx和useReducer的基本使用,本文通過實例代碼給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-11-11
React項目打包發(fā)布到Tomcat頁面空白問題及解決
這篇文章主要介紹了React項目打包發(fā)布到Tomcat頁面空白問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06

