在 React 里,Fiber 是 React 16.x 及后續版本采用的協調算法,它把渲染工作分割成多個小任務,讓 React 可以在渲染過程中暫停、恢復和復用任務,以此提升渲染性能與響應能力。在實際開發中,你無需直接操作 Fiber 節點,不過你可以借助 React 的 API 來利用 Fiber 的特性。下面從幾個方面為你講解 Fiber 的用法。
1. 異步渲染
Fiber 架構實現了異步渲染,這意味著 React 能在渲染期間暫停工作,處理高優先級的事件。你可以通過 React.lazy
和 Suspense
來實現代碼分割和異步加載組件。
import React, { lazy, Suspense } from 'react';// 異步加載組件
const LazyComponent = lazy(() => import('./LazyComponent'));function App() {return (<div><Suspense fallback={<div>Loading...</div>}><LazyComponent /></Suspense></div>);
}export default App;
2. 優先級調度
Fiber 架構支持任務優先級調度,借助 React.unstable_runWithPriority
函數,你能設置不同任務的優先級。
import React, { unstable_runWithPriority as runWithPriority } from 'react';function App() {const handleClick = () => {runWithPriority('userBlocking', () => {// 高優先級任務console.log('High priority task');});runWithPriority('normal', () => {// 普通優先級任務console.log('Normal priority task');});};return (<button onClick={handleClick}>Run tasks with different priorities</button>);
}export default App;
3. 時間切片
Fiber 利用時間切片技術,把渲染工作拆分成多個小任務,避免長時間阻塞主線程。在 React 中,你可以使用 React.memo
來對組件進行記憶化,減少不必要的渲染。
import React from 'react';// 記憶化組件
const MemoizedComponent = React.memo(({ data }) => {return <div>{data}</div>;
});function App() {const [count, setCount] = React.useState(0);return (<div><button onClick={() => setCount(count + 1)}>Increment</button><MemoizedComponent data={count} /></div>);
}export default App;
總結
- 異步渲染:借助
React.lazy
和Suspense
實現代碼分割和異步加載組件。 - 優先級調度:使用
React.unstable_runWithPriority
函數設置任務優先級。 - 時間切片:通過
React.memo
記憶化組件,減少不必要的渲染。
Fiber 是 React 16.x 及以后版本所采用的協調算法,其核心目標在于提升 React 應用的渲染性能和響應能力。下面詳細介紹 React Fiber 的核心技術點:
核心技術
1. 架構目標與動機
- 渲染性能優化:傳統的協調算法在處理大型組件樹時,可能會出現長時間阻塞主線程的情況,導致頁面卡頓。Fiber 通過將渲染任務拆分成多個小任務,允許在渲染過程中暫停、恢復和重新排序任務,避免長時間占用主線程,從而提升渲染性能。
- 優先級調度:Fiber 架構支持任務優先級調度,能夠根據任務的重要性和緊急程度對任務進行排序,優先處理高優先級的任務,如用戶交互事件,提高應用的響應能力。
2. 核心概念
- Fiber 節點:Fiber 節點是 Fiber 架構中的基本單元,每個 React 元素都對應一個 Fiber 節點。Fiber 節點包含了組件的狀態、屬性、副作用等信息,同時還維護了與其他 Fiber 節點的關系,如父節點、子節點和兄弟節點。
- Fiber 樹:由多個 Fiber 節點組成的樹形結構,代表了 React 應用的組件樹。Fiber 樹有兩棵,分別是
current
樹和workInProgress
樹。current
樹表示當前屏幕上顯示的內容,workInProgress
樹是正在構建的新樹,構建完成后會替換current
樹。 - 任務調度:Fiber 架構將渲染任務拆分成多個小任務,每個任務對應一個 Fiber 節點的處理。調度器會根據任務的優先級和時間片來決定何時執行任務,確保高優先級任務能夠及時處理。
3. 工作流程
- 調度階段(Scheduler):當組件的狀態或屬性發生變化時,React 會創建一個新的
workInProgress
樹,并將任務添加到調度器中。調度器會根據任務的優先級和時間片來決定何時執行任務。如果當前有高優先級的任務(如用戶交互事件),調度器會暫停當前正在執行的任務,優先處理高優先級任務。 - 協調階段(Reconciler):調度器選擇一個任務后,會將其交給協調器處理。協調器會遞歸遍歷
workInProgress
樹,比較current
樹和workInProgress
樹的差異,標記出需要更新、插入或刪除的節點。這個過程是可以暫停和恢復的,因為每個 Fiber 節點的處理都是一個獨立的小任務。 - 提交階段(Renderer):當協調階段完成后,所有的差異都已經標記好。提交階段會將這些差異一次性應用到真實 DOM 上,更新頁面顯示。提交階段是不可中斷的,確保頁面的一致性。
4. 優先級調度
- 任務優先級:Fiber 架構定義了多種任務優先級,如
ImmediatePriority
(最高優先級,立即執行)、UserBlockingPriority
(用戶交互相關的高優先級任務)、NormalPriority
(普通優先級任務)、LowPriority
(低優先級任務)和IdlePriority
(空閑時執行的任務)。 - 優先級調度算法:調度器會根據任務的優先級和時間片來決定任務的執行順序。高優先級的任務會優先執行,并且可以中斷低優先級的任務。當高優先級任務執行完成后,低優先級任務會繼續執行。
5. 異步渲染
- 時間切片:Fiber 利用時間切片技術,將渲染工作拆分成多個小任務,每個任務執行一段時間后暫停,將控制權交還給主線程,讓主線程有機會處理其他事件,如用戶交互、動畫等。這樣可以避免長時間阻塞主線程,提高應用的響應能力。
- Suspense 和 Lazy 組件:Fiber 架構支持異步加載組件,通過
React.lazy
和Suspense
可以實現代碼分割和異步渲染。當組件需要異步加載時,Suspense
組件可以顯示一個加載提示,直到組件加載完成。
6. 副作用處理
- 副作用(Effect):在 React 中,副作用是指那些會影響外部環境的操作,如數據獲取、訂閱、DOM 操作等。Fiber 架構通過
useEffect
和useLayoutEffect
等 Hooks 來處理副作用。 - 副作用調度:副作用的執行也遵循優先級調度原則。
useEffect
會在提交階段之后異步執行,不會阻塞頁面渲染;useLayoutEffect
會在提交階段同步執行,用于處理需要立即更新 DOM 的副作用。