文章目錄
- 前言
- ? 1. JSX 是什么?
- 🔧 2. 編譯后的樣子(核心機制)
- 🧱 3. `React.createElement` 做了什么?
- 🧠 4. JSX 與組件的關系
- 🔄 5. JSX 到真實 DOM 的過程
- 📘 6. JSX 與 Fragment、條件渲染等底層行為
- ?? 7. 注意事項
- ? 總結
- JSX 編譯后如何通過 Fiber 架構驅動渲染更新
- ? 一、React 渲染整體流程概覽(React 18+)
- 🧠 二、什么是 Fiber 架構?
- 📦 一個 Fiber 節點結構簡化如下:
- 🔄 三、Reconciliation(協調 / diff)機制
- Diff 規則核心簡化:
- ?? 四、Commit 階段(更新真實 DOM)
- ?? 五、Concurrent Mode(React 18)
- 🌟 調度示意(非阻塞渲染):
- 📌 六、雙緩沖機制(雙 Fiber Tree)
- 🎯 七、性能優化的啟示
- ? 總結:JSX 到 DOM 的底層機制主線
- ?? React Fiber 調度與中斷機制:時間切片、優先級調度、任務恢復
- ? 1. 為什么需要中斷渲染?
- 問題:
- ? 2. Fiber 如何解決這個問題?
- 🎯 利用:
- 📦 3. 任務調度:Scheduler 的優先級系統
- ? 4. 時間切片機制(Time Slicing)
- 🔁 5. 中斷與恢復機制
- ?? 6. Concurrent 模式的核心優勢
- 🧠 7. 示例:startTransition 與中斷渲染
- ? 8. 總結:Fiber 調度機制的精髓
- 📘 延伸(可選深入)
前言
ReactJS 中的 JSX(JavaScript XML)看起來像 HTML,但它其實只是語法糖,在底層是被編譯成 React.createElement(...)
調用的 JavaScript 代碼。理解其底層機制對優化性能、調試問題、使用 Hooks 等非常重要。
? 1. JSX 是什么?
JSX 是 JavaScript 的語法擴展,允許你這樣寫 UI:
const element = <h1>Hello, world!</h1>;
它看起來像 HTML,但不是。它不會被瀏覽器直接執行,而是會在構建階段被轉譯為 JavaScript。
🔧 2. 編譯后的樣子(核心機制)
這段代碼:
const element = <h1 className="title">Hello</h1>;
會被 Babel 編譯為:
const element = React.createElement('h1',{ className: 'title' },'Hello'
);
等價于:
{type: 'h1',props: {className: 'title',children: 'Hello'}
}
最終,React 用這些對象來構建虛擬 DOM(Virtual DOM)。
🧱 3. React.createElement
做了什么?
它會返回一個React 元素對象:
{$$typeof: Symbol(react.element),type: 'h1',key: null,ref: null,props: {className: 'title',children: 'Hello'},_owner: null
}
這是一個純 JS 對象,描述了 UI 的結構。不是 DOM 節點,還沒有真正渲染。
🧠 4. JSX 與組件的關系
JSX 中也可以使用組件:
<MyButton text="Click me" />
被編譯為:
React.createElement(MyButton, { text: "Click me" });
最終調用你自己寫的 MyButton(props)
函數,返回另一個 createElement(...)
。
🔄 5. JSX 到真實 DOM 的過程
- JSX 被編譯為
React.createElement(...)
- React 構建虛擬 DOM 樹
- React 將虛擬 DOM diff(比對)舊的 DOM 樹
- React 使用 DOM API 更新真實 DOM(插入、刪除、替換節點)
📘 6. JSX 與 Fragment、條件渲染等底層行為
<></>
→React.createElement(React.Fragment, null, ...)
- 條件渲染:
{condition && <div>Yes</div>}
→ 三元或邏輯判斷 - 循環渲染:
{list.map(item => <li>{item}</li>)}
→ 多次 createElement 調用
?? 7. 注意事項
特性 | 底層意義 |
---|---|
JSX 只能有一個根節點 | 因為 React.createElement 只能返回一個元素 |
不支持 if 語句直接寫在 JSX | JSX 是表達式,需要用三元或外部邏輯 |
自閉和標簽 <MyComp /> | 轉譯為 React.createElement(MyComp) |
不能直接渲染對象 | [object Object] 錯誤是因為 createElement 接收了非法 children |
? 總結
概念 | 作用 |
---|---|
JSX | React 的語法糖,用來描述 UI 結構 |
Babel | 把 JSX 編譯為 React.createElement() |
React.createElement | 創建虛擬 DOM 描述對象 |
虛擬 DOM | 一個 JS 對象樹,最終映射為真實 DOM |
渲染機制 | Diff + 更新 DOM 節點(最小化操作) |
JSX 編譯后如何通過 Fiber 架構驅動渲染更新
這一主線,系統講解 React 的底層工作機制,包括:
? 一、React 渲染整體流程概覽(React 18+)
graph TD
A[JSX] --> B[createElement]
B --> C[構建虛擬 DOM]
C --> D[Fiber 架構構建 Fiber Tree]
D --> E[Reconciliation(diff)]
E --> F[Commit 階段:更新真實 DOM]
🧠 二、什么是 Fiber 架構?
Fiber 是 React 從 v16 開始的核心架構,其主要目標是:
- 支持任務中斷(可暫停)
- 支持異步渲染(并發模式)
- 增強調度控制
- 支持優先級(Urgent、Normal、Idle)
Fiber = 一種“工作單元”結構,用鏈表組織虛擬 DOM,便于逐個處理、可打斷、可恢復
📦 一個 Fiber 節點結構簡化如下:
interface Fiber {type: string | FunctionComponentstateNode: HTMLElement | nullchild: Fiber | nullsibling: Fiber | nullreturn: Fiber | nullalternate: Fiber | null // 雙緩存機制effectTag: 'UPDATE' | 'PLACEMENT' | 'DELETION'
}
🔄 三、Reconciliation(協調 / diff)機制
目的:比較新舊 virtual DOM,找到最小變更,生成 effectList 用于更新真實 DOM。
Diff 規則核心簡化:
- 同層比較:只比較同級節點
- Key 區分同類型組件:用于
map
渲染性能優化 - 類型不同 → 全替換
- 類型相同 → 嘗試復用
?? 四、Commit 階段(更新真實 DOM)
當 Fiber 樹構建完畢后,進入 commit 階段:
// commitWork
switch (fiber.effectTag) {case 'PLACEMENT': // 插入parent.appendChild(fiber.stateNode);break;case 'UPDATE': // 屬性或內容變更updateDOM(fiber.stateNode, oldProps, newProps);break;case 'DELETION':parent.removeChild(fiber.stateNode);break;
}
?? 五、Concurrent Mode(React 18)
React 18 引入并發渲染模式,依賴 Fiber 實現:
特性 | 描述 |
---|---|
startTransition | 標記可中斷更新(非緊急) |
自動批處理 | setState 自動分組,不再需要 unstable_batchedUpdates |
useDeferredValue | 延遲非關鍵狀態同步更新 |
useTransition | 標記 UI “pending” 狀態,支持 loading skeleton 等過渡體驗 |
ReactDOM.createRoot | 默認進入 Concurrent 模式 |
🌟 調度示意(非阻塞渲染):
startTransition(() => {setValue(input);
})
React 會調度優先級高的操作(如輸入)先渲染,低優先的任務稍后處理。
📌 六、雙緩沖機制(雙 Fiber Tree)
React 使用 current
和 workInProgress
兩棵 Fiber Tree,交替使用:
current | 正在顯示的 UI |
---|---|
workInProgress | 當前計算的新狀態 |
當 Reconciliation 完成,React 會“交換”兩棵樹,實現 快照切換。
🎯 七、性能優化的啟示
場景 | 原因 | 優化策略 |
---|---|---|
大量列表重復渲染 | Key 設計不當導致全部 diff | 用穩定 Key |
卡頓嚴重 | 所有狀態更新同步 | 使用 startTransition , useDeferredValue |
多組件嵌套,重渲染過多 | props 未 memo | 使用 React.memo 、useMemo , useCallback |
復雜條件渲染 | JSX 重計算多 | 使用懶加載 React.lazy , Suspense |
? 總結:JSX 到 DOM 的底層機制主線
階段 | 關鍵內容 |
---|---|
編譯 | JSX → createElement → 虛擬 DOM |
構建 | Fiber 樹結構,鏈表連接 |
diff | Reconciliation 識別變化 |
更新 | commit 階段執行 effect list 操作真實 DOM |
并發 | Fiber 允許中斷、恢復、優先級調度 |
優化 | 利用 Hook + memo + key + transition |
?? React Fiber 調度與中斷機制:時間切片、優先級調度、任務恢復
React Fiber 架構最大的突破之一就是它將渲染任務拆分為“工作單元”(Fiber 節點),并使用瀏覽器的空閑時間或非阻塞方式來執行這些任務。
? 1. 為什么需要中斷渲染?
問題:
React 早期(v15 及以前)渲染是同步的:
ReactDOM.render(<App />, root);
如果組件樹很大,JS 線程會被“卡死”,導致:
- 輸入卡頓
- 動畫掉幀
- 無法響應用戶操作
? 2. Fiber 如何解決這個問題?
🧠 核心思想:把渲染拆成很多小任務,用瀏覽器空閑時間分批執行,并可中途暫停與恢復。
🎯 利用:
requestIdleCallback(callback)
或(React 18 起)用:
scheduler.unstable_scheduleCallback(priority, callback)
📦 3. 任務調度:Scheduler 的優先級系統
React 使用內部調度器(scheduler
)給任務分配優先級:
調度級別 | 描述 | 示例 |
---|---|---|
Immediate (最高) | 立刻執行 | setState 同步 |
UserBlocking | 用戶操作相關 | 輸入、點擊 |
Normal | 默認更新 | 內容變化 |
Low | 非關鍵 | 動畫、日志 |
Idle | 不重要 | 預加載 |
? 4. 時間切片機制(Time Slicing)
Fiber 會把任務拆成一個個 unit of work,然后循環調度:
while (nextUnitOfWork && shouldYield() === false) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
shouldYield()
檢查是否要讓位給瀏覽器,防止掉幀。
function shouldYield() {return performance.now() >= deadline;
}
🔁 5. 中斷與恢復機制
如果 shouldYield()
為 true
,Fiber 會 中斷當前工作,然后把當前狀態保存在 workInProgress
上,下次從這個點繼續:
// workInProgress 保存當前 fiber 的指針鏈表狀態
瀏覽器空閑后,React 會再次調度:
requestIdleCallback(workLoop)
?? 6. Concurrent 模式的核心優勢
能力 | 說明 |
---|---|
? 中斷 | 渲染過程可被暫停 |
🔁 恢復 | 下一幀繼續渲染剩余部分 |
?? 優先級 | 用戶輸入優先渲染,非關鍵可延后 |
🎨 更流暢 | 輸入不卡頓,動畫更自然 |
🧠 更智能 | 可實現并行 diff、預渲染、Suspense fallback 等功能 |
🧠 7. 示例:startTransition 與中斷渲染
import { startTransition } from 'react'function handleInput(e) {const value = e.target.value// 非緊急更新,允許中斷startTransition(() => {setFilteredList(filterBigList(value))})
}
用戶打字不會因為
setFilteredList()
而卡頓,因為這是一個“可中斷更新”。
? 8. 總結:Fiber 調度機制的精髓
點 | 內容 |
---|---|
拆分 | Fiber 把渲染任務拆成小單元 |
調度 | 使用 scheduler 或 requestIdleCallback 進行執行調度 |
中斷 | shouldYield() 決定是否讓步給瀏覽器主線程 |
恢復 | 保存中間狀態于 Fiber,支持恢復渲染 |
優先級 | 按任務重要程度進行排序調度,保障交互流暢性 |
📘 延伸(可選深入)
如果你還想進一步了解:
Lane Model
(React 18 調度核心)- React Scheduler 實現(源碼級)
- Suspense + Fiber 如何協同暫停渲染樹
Concurrent Features
:如React.lazy
,Streaming SSR