在react函數(shù)組件中修改狀態(tài)會觸發(fā)整個函數(shù)組件的重載丧凤,重載過程中會導致函數(shù)中的方法重載和組件重新渲染捌锭,這個過程中有很多重載和重新渲染是不必要的俘陷,我們可以使用memo和useCallback方法來阻止不必要的性能消耗。
首先定義三個基礎(chǔ)組件舀锨,來觀察不使用上述方法之前的渲染情況:
在最外層父組件中聲明count狀態(tài)和更改count的方法setCount岭洲,并定義一個將count重置為0的方法傳遞給Foo組件,當我們觸發(fā)count更改時整個App函數(shù)都會重載坎匿,重載過程中會導致reset方法也被重載盾剩,App組件當中引入的Foo和Pure組件都會重新渲染。
如上圖所示替蔬,每次點擊按鈕都會觸發(fā)兩個子組件的重新渲染告私,但是事實上這兩個子組件的重新渲染是沒有必要的。
memo:
memo的作用是在組件重新渲染前確認內(nèi)部傳入的組件是否需要重新渲染承桥。
這里將Pure組件用memo方法進行嵌套驻粟。
然后再次點擊按鈕更改狀態(tài)觸發(fā)App組件的重新渲染
可以看到這里再次進行點擊,重新渲染的子組件就只有Foo了凶异,由于Pure內(nèi)部沒有狀態(tài)和屬性更改蜀撑,memo會判定該組件無需重新渲染
useCallback:
useCallback的作用是緩存一個函數(shù),并傳入相關(guān)的依賴項剩彬,只有在依賴項改變的時候才會重載函數(shù)
我們首先給Foo也包裹memo方法
點擊按鈕更改狀態(tài)觸發(fā)App組件的重新渲染
發(fā)現(xiàn)即使嵌套了memo酷麦,F(xiàn)oo組件還是會不斷重新渲染,原因是我們從父組件傳入的reset在父組件重載的過程中也被重載了喉恋,新的reset !== 上次傳入的reset沃饶,由于屬性發(fā)生了更改,因此被認為有必要進行重新渲染轻黑,這時就應(yīng)該用useCallback將reset方法進行緩存糊肤,阻止這種不必要的重新渲染。
此時再觸發(fā)狀態(tài)更改
兩個組件都只有初始化渲染氓鄙,不再觸發(fā)重新渲染了馆揉。
附代碼:
import React, { memo, useCallback, useState } from "react";
// 最外層父組件
function App() {
const [count, setCount] = useState(0)
const reset = useCallback(() => {
setCount(0)
}, [])
return (
<div className="App">
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>add</button>
<Foo reset={reset} />
<Pure />
</div>
);
}
// 接收函數(shù)
const Foo = memo(function Foo(props) {
console.log('Foo render...');
return (
<button onClick={props.reset}>
reset
</button>
)
})
// 純函數(shù)組件
const Pure = memo(function Pure() {
console.log('pureComponent render...');
return (
<div>pureComponent</div>
)
})
export default App;