React渲染的優(yōu)化方案
一、引子
react的渲染機制是非常獨特的,有別于 Vue 框架的渲染次數(shù)的優(yōu)化計算。React 很久以來就有PureComponent、shouldUpdate。Function component 又有了memo、useMemo、useCallback 這樣的函數(shù)工具,讓它成為有一定深度的前端框架。
怎么使用 useMemo 和 useCallback 是我們值得思考的點。
二、代碼范式
首先,假設(shè)大家對 React 都有一個基礎(chǔ)的入門水平,所以本文不再贅述“useMemo 和 useCallback ”基本用法。
2.1 Memo 緩存組件
引起重渲染的最常見的情況是,組件的 props。memo包裹著函數(shù)組件,針對props 參數(shù)的淺對比。
子組件的渲染有些情況,子組件控制不住,它受到父組件的參數(shù)影響。
function _Boxes({ boxes }: {
boxes: {
flex: number;
background: string;
}[]
}) {
return (
<div className="boxes-wrapper">
{boxes.map((boxStyles, index) => (
<div className="box" style={boxStyles} key={index} />
))}
</div>
);
}
const Boxes = memo(_Boxes);
2.2 父組件層面,對象使用 useMemo
作為 Box 的父組件,boxes 的傳參是一個對象,每次改變,它會生成一個全新的對象。這里要對 boxes 對象使用緩存(useMemo)。這樣,age 的改動將不會影響到 Box 的重渲染。
function App() {
const [age, setAge] = React.useState(0);
const [boxWidth, setBoxWidth] = React.useState(1);
const id = React.useId();
// Age 屬性的變更不會影響 boxes 屬性變化
const boxes = useMemo(() => {
return [
{ flex: boxWidth, background: 'hsl(345deg 100% 50%)' },
{ flex: 3, background: 'hsl(260deg 100% 40%)' },
{ flex: 1, background: 'hsl(50deg 100% 60%)' },
];
}, [boxWidth]);
return (
<>
<Boxes boxes={boxes} />
<section>
<button onClick={() => {
setAge(age + 1)
}}>
Increment age
</button>
<p>Hello! You are {age}.</p>
</section>
<section>
<label htmlFor={`${id}-box-width`}>
First box width:
</label>
<input
id={`${id}-box-width`}
type="range"
min={1}
max={5}
step={0.01}
value={boxWidth}
onChange={(event) => {
setBoxWidth(Number(event.target.value));
}}
/>
</section>
</>
);
}
2.3 context provider 最好用 useMemo
同理,參考《How To useContext With useReducer》,context provider 的 value 參數(shù)是一個很容易被遺忘的點,provider 可能會傳入一個對象,利用useMemo 或者 useCallback 來保護 App 組件不會做出過多重渲染。
const Main = () => {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// 利用useMemo 或者 useCallback 來保護 Context 不會做出過多重渲染
const contextValue = useMemo(() => {
return { state, dispatch };
}, [state, dispatch]);
return (
<MyContext.Provider value={contextValue}>
<App />
</MyContext.Provider>
)
}
2.4 其他
還有一種特殊情況是:不規(guī)范、分批的 Context 調(diào)用導致了頁面的重新渲染。針對一些老舊項目,以前的業(yè)務(wù)邏輯導致 Context 的調(diào)用混亂,已經(jīng)不是前面幾種方法能夠解決的。
解決方法:改動代碼,把多次 Context 調(diào)用整合為一次。
三、補救防范
3.1 斷點查看調(diào)用堆棧
利用 Chrome 原生調(diào)試工具打斷點,看每一行代碼的堆棧信息。這種方式最為原始但是它往往“行之有效”。
3.2 devtool 查看渲染次數(shù)和渲染堆棧
React Devtool 的 Profiler 能協(xié)助我們排查 React 渲染次數(shù)和渲染堆棧。
- 點擊 Profiler 的記錄圓圈
- 刷新頁面或者做其他操作
- 停止記錄
- 參考快照記錄

同時,我們還能夠通過“highlight updates when components render”來可視化整個渲染過程。

3.3 渲染打印工具
ahooks的useWhyDidYouUpdate
該函數(shù)能夠幫助開發(fā)者排查是哪個屬性改變導致了組件的 rerender,但是更多集中在 props、state,開發(fā)者需要主動去縮小范圍,它起到輔助打印的工作,如果是 Context 或者更外側(cè)的數(shù)據(jù)變動,效果不見得達到效果。
Welldone Software 的 why-did-you-render
該工具能全局打印 rerender 日志,但是在復雜項目當中,它的打印較為混亂,不一定能夠很好的發(fā)現(xiàn)問題。
四、總結(jié)
React 的渲染優(yōu)化有非常多篇博客已經(jīng)聊過,但是還是“No Silver Bullet”,沒有最佳方案。特別在一些數(shù)據(jù)流非常復雜的前端工程項目當中。
React 的前端項目能夠劃分為:聰明組件和懶惰組件。聰明組件負責的內(nèi)容是頁面邏輯的數(shù)據(jù)流向,懶惰組件負責的是樣式的渲染,數(shù)據(jù)流越是清晰,代碼可維護性越強。
以下是我個人的代碼編寫建議:
- 不要把所有數(shù)據(jù)都往 Context 里面放,只有極其核心,多個頁面都復用情況。
- 簡單的頁面,盡量以聰明組件和懶惰組件的方式來處理。
- 如果已經(jīng)出現(xiàn)數(shù)據(jù)流混亂的情況下,合理使用 memo,或者狀態(tài)管理工具(例如zustand、jotai等)讓代碼數(shù)據(jù)流盡量走向清晰,初始化主路徑盡量批量渲染好。
雖然有很多分析工具,但是它們更多是輔助,最重要還是要通過人工分析。重點要分析出渲染次數(shù)過多的代碼,做出針對性地處理。
以上就是React渲染的優(yōu)化方案的詳細內(nèi)容,更多關(guān)于React渲染優(yōu)化的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React中setState/useState的使用方法詳細介紹
這篇文章主要介紹了React中setState/useState的使用方法,useState 和 setState 在React開發(fā)過程中 使用很頻繁,但很多人都停留在簡單的使用階段,并沒有正在了解它們的執(zhí)行機制2023-04-04
Native?Memory?Tracking追蹤區(qū)域示例分析
這篇文章主要為大家介紹了Native?Memory?Tracking追蹤區(qū)域示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
antd?3.x?Table組件如何快速實現(xiàn)虛擬列表詳析
這篇文章主要給大家介紹了關(guān)于antd?3.x?Table組件如何快速實現(xiàn)虛擬列表的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家學習或者使用antd具有一定的參考學習價值,需要的朋友可以參考下2022-11-11
react-router v4如何使用history控制路由跳轉(zhuǎn)詳解
這篇文章主要給大家介紹了關(guān)于react-router v4如何使用history控制路由跳轉(zhuǎn)的相關(guān)資料,文中通過示例代碼介紹的的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-01-01
解決antd的Table組件使用rowSelection屬性實現(xiàn)多選時遇到的bug
這篇文章主要介紹了解決antd的Table組件使用rowSelection屬性實現(xiàn)多選時遇到的bug問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08

