深入理解React 渲染機(jī)制
引言
React 作為當(dāng)今最流行的前端框架之一,其高效的渲染機(jī)制是核心優(yōu)勢(shì)。理解 React 如何渲染 UI,對(duì)于性能優(yōu)化至關(guān)重要。本文將深入探討虛擬 DOM、Diff 算法、Fiber 架構(gòu)以及完整的渲染流程。
虛擬 DOM 原理與優(yōu)勢(shì)
虛擬 DOM(Virtual DOM)是 React 的核心概念,它是一個(gè)輕量級(jí)的 JavaScript 對(duì)象,用來描述真實(shí) DOM 的結(jié)構(gòu)。
工作原理:
- 首次渲染時(shí),React 創(chuàng)建虛擬 DOM 樹并映射到真實(shí) DOM
- 狀態(tài)變化時(shí),生成新的虛擬 DOM 樹
- 通過 Diff 算法比較兩棵樹的差異
- 將最小變更應(yīng)用到真實(shí) DOM
核心優(yōu)勢(shì):
- 減少直接操作真實(shí) DOM 的次數(shù)
- 批量更新,提升性能
- 跨平臺(tái)能力(React Native 等)
// 虛擬 DOM 示例
const element = {
type: 'div',
props: {
className: 'container',
children: {
type: 'h1',
props: { children: 'Hello React' }
}
}
};
Diff 算法三大策略
React 的 Diff 算法通過三大策略將 O(n³) 復(fù)雜度優(yōu)化到 O(n):
1. 同層比較
React 只比較同一層級(jí)的節(jié)點(diǎn),不會(huì)跨層級(jí)比較。如果節(jié)點(diǎn)類型不同,直接銷毀舊節(jié)點(diǎn)并創(chuàng)建新節(jié)點(diǎn)。
// 同層比較示例 // 舊樹 // 新樹 <div> <div> <Component /> <Component /> </div> </div> // ? 只比較 div 的子節(jié)點(diǎn)
2. 類型判斷
節(jié)點(diǎn)類型相同時(shí),復(fù)用節(jié)點(diǎn);類型不同時(shí),銷毀重建。
// 類型相同 - 復(fù)用 <div className="old"> → <div className="new"> // 類型不同 - 重建 <div> → <span> // 銷毀 div,創(chuàng)建 span
3. Key 的作用
Key 幫助 React 識(shí)別哪些元素發(fā)生了變化,特別在列表渲染中至關(guān)重要。
// ? 不推薦 - 使用索引作為 key
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}
// ? 推薦 - 使用唯一 ID
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
Fiber 架構(gòu)詳解
React 16 引入的 Fiber 架構(gòu)解決了大規(guī)模組件樹渲染阻塞的問題。
節(jié)點(diǎn)結(jié)構(gòu)
每個(gè) Fiber 節(jié)點(diǎn)包含:
type: 組件類型props: 屬性return: 父節(jié)點(diǎn)child: 子節(jié)點(diǎn)sibling: 兄弟節(jié)點(diǎn)effectTag: 副作用標(biāo)記
雙緩沖機(jī)制
Fiber 使用雙緩沖(Double Buffering)技術(shù):
- current 樹: 當(dāng)前屏幕上顯示的 Fiber 樹
- workInProgress 樹: 正在構(gòu)建的新 Fiber 樹
渲染完成后,直接替換指針,實(shí)現(xiàn)快速切換。
任務(wù)優(yōu)先級(jí)
Fiber 將渲染任務(wù)拆分為可中斷的小單元,根據(jù)優(yōu)先級(jí)調(diào)度:
| 優(yōu)先級(jí) | 場(chǎng)景 |
|---|---|
| Immediate | 用戶輸入、文本選擇 |
| UserBlocking | 點(diǎn)擊、滾動(dòng) |
| Normal | 網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)加載 |
| Low | 分析上報(bào) |
| Idle | 后臺(tái)任務(wù) |
完整渲染流程
React 渲染分為兩個(gè)階段:
Render 階段(可中斷)
- 從根 Fiber 開始遍歷
- 調(diào)用組件的 render 方法
- 比較新舊虛擬 DOM,標(biāo)記變更
- 可被高優(yōu)先級(jí)任務(wù)中斷
// Render 階段示例
function App() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
// 點(diǎn)擊時(shí)觸發(fā) Render 階段
Commit 階段(不可中斷)
- 應(yīng)用所有變更到真實(shí) DOM
- 調(diào)用生命周期鉤子(componentDidMount 等)
- 觸發(fā) useEffect 回調(diào)
- 必須同步完成,不可中斷
Render 階段 → 標(biāo)記變更 → Commit 階段 → 更新 DOM
(可中斷) (不可中斷)
性能優(yōu)化實(shí)踐
1. 使用 React.memo
const MemoComponent = React.memo(({ data }) => {
return <div>{data}</div>;
});
// 僅在 props 變化時(shí)重新渲染
2. 使用 useMemo 緩存計(jì)算結(jié)果
const expensiveValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
// 依賴不變時(shí)復(fù)用緩存值
3. 使用 useCallback 緩存函數(shù)
const handleClick = useCallback(() => {
doSomething(a, b);
}, [a, b]);
// 避免子組件因函數(shù)引用變化而重渲染
4. 列表渲染優(yōu)化
// 虛擬列表 - 只渲染可見區(qū)域
import { FixedSizeList } from 'react-window';
<FixedSizeList
height={500}
itemCount={1000}
itemSize={35}
>
{({ index, style }) => (
<div style={style}>Item {index}</div>
)}
</FixedSizeList>
5. 代碼分割
// 懶加載組件
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
);
}
總結(jié)
React 渲染機(jī)制的核心要點(diǎn):
- 虛擬 DOM 減少真實(shí) DOM 操作,提升性能
- Diff 算法 通過同層比較、類型判斷、Key 識(shí)別實(shí)現(xiàn) O(n) 復(fù)雜度
- Fiber 架構(gòu) 支持可中斷渲染和任務(wù)優(yōu)先級(jí)調(diào)度
- 雙階段渲染 Render 可中斷,Commit 不可中斷
- 性能優(yōu)化 合理使用 memo、useMemo、useCallback 等工具
理解這些機(jī)制,能幫助我們?cè)陂_發(fā)中做出更優(yōu)的性能決策,構(gòu)建流暢的用戶體驗(yàn)。
到此這篇關(guān)于深入理解React 渲染機(jī)制的文章就介紹到這了,更多相關(guān)React 渲染機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Ant Design與Ant Design pro入門使用教程
Ant Design 是一個(gè)服務(wù)于企業(yè)級(jí)產(chǎn)品的設(shè)計(jì)體系,組件庫是它的 React 實(shí)現(xiàn),antd 被發(fā)布為一個(gè) npm 包方便開發(fā)者安裝并使用,這篇文章主要介紹了Ant Design與Ant Design pro入門,需要的朋友可以參考下2023-12-12
解決react中useState狀態(tài)異步更新的問題
本文主要介紹了react中useState狀態(tài)異步更新的問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
詳解基于webpack搭建react運(yùn)行環(huán)境
本篇文章主要介紹了詳解基于webpack搭建react運(yùn)行環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
react render的原理及觸發(fā)時(shí)機(jī)說明
這篇文章主要介紹了react render的原理及觸發(fā)時(shí)機(jī)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
React+TS+IntersectionObserver實(shí)現(xiàn)視頻懶加載和自動(dòng)播放功能
通過本文的介紹,我們學(xué)習(xí)了如何使用 React + TypeScript 和 IntersectionObserver API 來實(shí)現(xiàn)一個(gè)視頻播放控制組件,該組件具有懶加載功能,只有在用戶滾動(dòng)頁面且視頻進(jìn)入視口時(shí)才開始下載視頻資源,需要的朋友可以參考下2023-04-04

