React.memo 允許你的組件在 props 沒有改變的情況下跳過重新渲染。
const MemoizedComponent = memo(SomeComponent, arePropsEqual?)
React 通常在其父組件重新渲染時重新渲染一個組件。你可以使用 memo 創建一個組件,當它的父組件重新渲染時,只要它的新 props 與舊 props 相同時,React 就不會重新渲染它。這樣的組件被稱為 記憶化的(memoized)
組件。
一、未使用memo
1. 代碼
import { useState } from "react";// 未做memo記憶化之前
function Son() {console.log('子組件重新渲染');return (<><div>子組件</div></>)
}function App() {const [count1, setCount1] = useState(0);return (<><div>父組件:{count1} <button onClick={() => setCount1(count1 + 1)}>+</button></div><Son /></>)
}export default App;
2.運行效果
二、使用memo
1. 代碼
import { memo,useState } from "react";// 使用memo
const MemoSon = memo(function Son() {console.log('子組件重新渲染');return (<><div>子組件</div></>)
})function App() {const [count1, setCount1] = useState(0);return (<><div>父組件:{count1} <button onClick={() => setCount1(count1 + 1)}>+</button></div><MemoSon /></>)
}export default App;
2.運行效果
三、props的比較機制
在使用 memo 緩存組件之后,React會對 每一個prop
使用 Object.is
比較新值和老值,返回true,表示沒有變化:
-
prop 是簡單類型
Object.is(3, 3) => true
沒有變化 -
prop 是引用類型(對象/數組)
Object.is([], []) => false
有變化,React 只關心引用是否變化
四、 prop為引用類型,如何避免子組件重新渲染?
當prop為簡單類型時很好理解,但當prop是引用類型時,即使prop的值內容不變,但是引用地址不同,也會觸發重新渲染,如下示例:
1. 代碼
import { memo, useState } from "react";// 3. prop為引用類型
const MemoSon = memo(function Son({list}) {console.log('子組件再次渲染');return (<><div>子組件:{list}</div></>)
})function App() {const [count1, setCount1] = useState(0);// 3. prop為引用類型const list = [1,2,3];return (<><div>父組件:{count1} <button onClick={() => setCount1(count1 + 1)}>+</button></div>{/* 3. prop為引用類型 */}<MemoSon list={list} /></>)
}export default App;
2. 效果
3. 使用useMemo
緩存list
...// 保證引用穩定 => useMemo 在組件渲染的過程中緩存一個值const list = useMemo(() => {return [1,2,3];}, []);...
4. 效果
五、完整代碼
import { memo, useMemo, useState } from "react";// 1. 未使用memo
/* function Son() {console.log('子組件再次渲染');return (<><div>子組件</div></>)
} */// 2. memo 記憶化后
/* const MemoSon = memo(function Son() {console.log('子組件再次渲染');return (<><div>子組件</div></>)
}) */// 3. prop為引用類型
// 傳遞引用類型的 prop,比較的是新值和舊值的引用是否相等,當父組件的函數重新執行時,實際上形成的是新的引用
const MemoSon = memo(function Son({list}) {console.log('子組件再次渲染');return (<><div>子組件:{list}</div></>)
})function App() {const [count1, setCount1] = useState(0);// 3.1 prop為引用類型 直接定義一個 list// const list = [1,2,3];// 3.2 prop為引用類型,使用 useMemo 緩存list// 保證引用穩定 => useMemo 在組件渲染的過程中緩存一個值const list = useMemo(() => {return [1,2,3];}, []);return (<><div>父組件:{count1} <button onClick={() => setCount1(count1 + 1)}>+</button></div>{/* // 1. 未使用memo */}{/* <Son /> */}{/* // 2. 使用memo */}{/* <MemoSon /> */}{/* 3. prop為引用類型 */}<MemoSon list={list} /></>)
}export default App;