React Hooks底層執行邏輯詳解、自定義Hooks、FiberScheduler

React Hooks底層執行邏輯詳解

React Hooks 在表面上看像普通的函數調用,背后卻隱藏著一套復雜而高效的運行時機制。要理解 React Hooks 的底層執行邏輯,需要從 React 如何管理組件的狀態與副作用入手。


🧠 一、React 為什么引入 Hooks?

在 class 組件中,狀態邏輯分散、復用困難(通過 HOC、render props 實現)。Hooks 通過“函數組件 + 閉包 + 順序調用”機制,解決了這些問題,讓函數組件擁有“類”的能力。


🔍 二、Hooks 的核心機制:調用順序與數組棧

? 核心思想:

React 內部為每個組件實例維護一個 “Hook 調用棧”(本質上是一個數組),Hooks 的執行順序嚴格依賴于你在函數中書寫的順序

舉個例子:

function MyComponent() {const [count, setCount] = useState(0)    // 第一個 Hook(索引 0)const [name, setName] = useState('')     // 第二個 Hook(索引 1)
}

React 內部邏輯可以抽象為偽代碼:

let hookIndex = 0
const hooks = []function useState(initialValue) {const currentIndex = hookIndexif (isMount) {hooks[currentIndex] = typeof initialValue === 'function' ? initialValue() : initialValue}const setState = (newValue) => {hooks[currentIndex] = newValuetriggerComponentUpdate()}hookIndex++return [hooks[currentIndex], setState]
}

?? 所以:每次重新渲染組件時,React 都會以相同順序重新執行 useXXX(),來匹配狀態數組中的值。


🔧 三、Hooks 的執行流程(React 內部機制)

🧩 每次組件渲染時:

  1. 當前組件會進入 render phase

  2. React 初始化 fiberNode.memoizedState(Hook 存儲區)

  3. 每次調用一個 Hook(如 useStateuseEffect):

    • React 用當前的 hookIndex 取出對應位置的值
    • 更新完后 hookIndex++
  4. 所有 Hook 調用完畢后:

    • memoizedState 就是這個組件的 Hook 狀態鏈
    • React 將其掛在 fiber 樹上,供下一次渲染使用

?? 四、不同 Hook 的底層行為

1?? useState

  • 在首次渲染時保存初始值
  • 后續調用 setState 會觸發組件更新,并保留新值在狀態數組中

2?? useEffect

  • 注冊副作用及清理函數
  • 保存依賴數組,用于下一次渲染對比
  • 在 commit 階段執行副作用

3?? useRef

  • 保存一個 { current: ... } 對象
  • 是在 Hook 數組中創建的穩定引用,不會重新創建

4?? useMemo / useCallback

  • 保存返回值或函數引用
  • 對比依賴數組決定是否復用舊值

📊 五、Hook 狀態存儲結構:Fiber Node

每個組件的所有 Hook 狀態,都掛載在它自己的 Fiber Node 上的 memoizedState 字段中,它實際上是一個單鏈表結構

FunctionComponentFiberNode
└── memoizedState --> HookState(useState) └── next --> HookState(useEffect) └── next --> ...

這個結構意味著:

  • 每個 Hook 對應鏈表中的一個節點
  • 遍歷順序必須與調用順序保持一致,否則狀態將錯位(所以 Hooks 不能寫在條件語句中)

🚨 六、為什么 Hooks 不能放在 if 語句里

因為狀態順序是通過“調用順序 + 索引”來維護的。如果你這樣寫:

if (someCondition) {useState(...) // ?? 不一定會調用
}

那么下一次渲染時,Hook 的數量或順序可能變化,導致狀態錯亂(取到了別的 Hook 的狀態)!

React 會通過內部開發環境檢查這些不規范用法。


🧬 七、Hook 觸發組件更新的機制

當調用 setState(newVal)

  1. 會創建一個更新對象,加入到組件的更新隊列
  2. 標記當前 Fiber 為“需要更新”
  3. 觸發 React Scheduler 安排任務(基于優先級)
  4. 進入 render phase,重新執行組件函數(重新執行所有 Hooks)
  5. 比較 Fiber 樹 → 更新 DOM

🧪 八、一個模擬實現:useState

let hookStates = []
let hookIndex = 0function useState(initialValue) {const currentIndex = hookIndexhookStates[currentIndex] = hookStates[currentIndex] || initialValuefunction setState(newVal) {hookStates[currentIndex] = newValrender()}hookIndex++return [hookStates[currentIndex], setState]
}function render() {hookIndex = 0ReactDOM.render(<App />, document.getElementById('root'))
}

? 九、總結:Hooks 底層關鍵點

機制說明
順序執行原則Hooks 必須按照一致順序調用
狀態數組/鏈表結構每個 Hook 都在 Fiber 節點的狀態鏈表中占一項
更新觸發原理setState 會觸發組件的調度和重新渲染
Hooks 本質React 自定義的一套狀態和副作用管理系統,依賴“閉包 + 引用 + 順序”維護狀態

自定義Hook

自定義 Hooks 是現代 React 中最重要的模式之一,用于在函數組件之間復用邏輯。它是一種在組件外提取公共邏輯的方式,優雅地替代了以前 class 組件中用 HOC 或 render props 的做法。


🧠 一、自定義 Hook 是什么?

自定義 Hook 就是一個以 use 開頭的 JavaScript 函數,內部可以調用其他 Hooks(如 useState、useEffect、useContext 等)

它并不需要擁有特殊的語法,而是遵守命名規范(以 use 開頭)和 Hook 規則(只能在頂層和 React 函數組件中調用)


🔧 二、基礎語法結構

function useMyHook() {const [state, setState] = useState(initialValue)// 可以包含副作用useEffect(() => {// 例如訂閱數據return () => {// 清理操作}}, [])return { state, setState }
}

使用方法:

function MyComponent() {const { state, setState } = useMyHook()return <div>{state}</div>
}

🛠? 三、常見自定義 Hook 示例

1?? useWindowSize:監聽窗口大小

import { useState, useEffect } from 'react'function useWindowSize() {const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight })useEffect(() => {const handleResize = () => {setSize({ width: window.innerWidth, height: window.innerHeight })}window.addEventListener('resize', handleResize)return () => window.removeEventListener('resize', handleResize)}, [])return size
}

2?? useFetch:封裝數據請求邏輯

import { useState, useEffect } from 'react'function useFetch(url) {const [data, setData] = useState(null)const [loading, setLoading] = useState(true)useEffect(() => {setLoading(true)fetch(url).then(res => res.json()).then(data => {setData(data)setLoading(false)})}, [url])return { data, loading }
}

使用:

const { data, loading } = useFetch('/api/user')

🧩 四、自定義 Hook 的使用場景

場景Hook 示例
狀態共享useForm, useTheme, useAuth
業務邏輯抽象usePagination, useLogin
操作 DOMuseScroll, useFocus
事件/副作用封裝useOnlineStatus, useDebounce
狀態機器或流程控制useWizard, useStepper

🚨 五、自定義 Hook 的注意事項

1. 必須以 use 開頭

否則 React 無法檢測是否遵守 Hook 的規則。

2. 遵循 Hook 規則(頂層調用)

  • 不要在 if、for、事件中調用 Hook
  • Hook 必須在函數組件或另一個 Hook 中使用
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述

Hooks 是按調用順序管理狀態的,調用順序必須穩定執行上下文必須是“可追蹤”的(函數組件或 Hook),否則 React 無法正確管理它們。

3. 避免副作用重復(加依賴)

useEffect(() => {// fetch or something
}, [url]) // 依賴項必須寫全

? 六、自定義 Hook vs HOC/Render Props

特性自定義 HookHOCRender Props
寫法簡潔? 非常簡潔? 會嵌套? 需要 props 回調
類型推導好? 原生支持? props 類型麻煩?
可組合性? 任意組合??
推薦程度? 推薦使用? 舊方式(不推薦)?(不推薦)

📦 七、如何組織自定義 Hook?

建議創建一個 hooks/ 文件夾,每個 Hook 一個文件。例如:

src/
├── hooks/
│   ├── useAuth.js
│   ├── useFetch.js
│   └── useWindowSize.js

? 總結

你應該使用自定義 Hook 的時候:
有重復邏輯(如監聽、請求、共享狀態等)
邏輯獨立但不涉及 UI
想增強可維護性和可測試性

如果你告訴我你項目中具體遇到的重復邏輯或問題,我可以幫你定制一個適合你項目的自定義 Hook 模板。是否要嘗試?


Fiber&Scheduler

在這里插入圖片描述
Fiber 架構 + Scheduler 是 React 實現 并發渲染 的核心。它們分別負責「任務的組織與執行邏輯」和「任務的調度與執行時機」。


🧠 一、React Fiber 架構詳解

Fiber 是 React 16 引入的全新架構,用來替代舊的 Stack Reconciler。它的設計目標是:

  • 任務可被拆分(增量渲染)
  • 渲染可中斷、恢復、重用
  • 支持并發調度

📦 1. Fiber 是什么?

一個 Fiber 就是一個組件的工作單元(Work Unit),它是一個 JavaScript 對象,描述了:

type FiberNode = {type: Function | string;key: string | null;child: FiberNode | null;sibling: FiberNode | null;return: FiberNode | null; // 父節點stateNode: any; // 組件實例memoizedProps: any;memoizedState: any;alternate: FiberNode | null; // 雙緩沖flags: number; // 副作用標記...
}

🧭 2. Fiber Tree 構建過程

每次更新時,React 會創建一棵新的 Fiber 樹(work-in-progress tree),由當前樹(current tree)復制并修改。

  • 雙緩沖機制:current & workInProgress 交替使用
  • 每個更新任務遞歸生成 Fiber 節點,構成完整 Fiber 樹

🔁 3. Fiber 的工作循環(核心階段)

🔨 Reconciliation(協調階段)
  • 調用組件函數(或類的 render)生成新的虛擬 DOM
  • 比較新舊 Fiber 樹,標記哪些節點需要變更
  • 構建 “Effect List”(副作用鏈表)
🚀 Commit(提交階段)
  • 根據 Effect List 執行真實的 DOM 操作(插入/刪除/更新)
  • 不可被打斷,必須同步完成

🕹? 二、Scheduler 調度器詳解

Scheduler 是 React 的調度核心,負責 管理 Fiber 的執行時機與優先級,使 React 擁有「可中斷」和「可恢復」的能力。


📋 1. 核心能力

  • 管理任務隊列
  • 計算任務優先級(Lanes)
  • 根據瀏覽器空閑時間切片執行
  • 決定是否讓出主線程(shouldYield

? 2. 時間切片(Time Slicing)

while (work && !shouldYield()) {work = performUnitOfWork(work);
}
  • 每次只做一小部分工作(一個 Fiber 節點)
  • 超出時間閾值就讓出執行權,避免卡住主線程

📊 3. 優先級系統(Lanes)

React 引入「Lanes(車道)」作為多優先級調度方案:

const NoLane = 0b00000
const SyncLane = 0b00001       // 同步優先級
const InputContinuousLane = 0b00010 // 用戶輸入優先
const DefaultLane = 0b00100
const IdleLane = 0b10000       // 最低優先

React 會根據任務類型分配 Lane,調度器根據當前空閑情況,調度最高優先的任務先執行。


?? 三、Fiber + Scheduler 協同流程圖

用戶觸發更新(如點擊按鈕)↓
Scheduler 收到任務,放入任務隊列↓
根據 Lane 決定優先級 & 是否立即執行↓
Fiber Tree 被構建(協調階段)↓
每個 Fiber 任務以時間切片形式執行↓
中途檢查 shouldYield(),必要時中斷↓
所有 Fiber 構建完成,進入 commit 階段↓
一次性提交 DOM 修改(同步執行)

🧩 總結:Fiber & Scheduler 分工

功能FiberScheduler
結構描述每個組件的渲染任務管理任務執行的優先級和時機
拆分任務將渲染工作拆成一個個 Fiber 節點將任務切片處理,防止阻塞主線程
可中斷機制通過時間切片,暫停和恢復渲染決定何時中斷、恢復和重新調度任務
優先級處理每個 Fiber 帶有優先級(lane)任務隊列按優先級排序

如果你需要我通過可視化圖解、源碼級解析(如 Scheduler 源碼調度流程),我也可以幫你補充。是否繼續?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/82157.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/82157.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/82157.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Windows命令實用工具——tcping 命令工具安裝及基礎使用

Windows命令實用工具——tcping 命令工具安裝及使用 一、tcping 命令簡介二、tcping 的安裝1、tcping 官網下載安裝包2、將軟件包復制到 Windws 系統的 System32 目錄下面3、查看 tcping 命令是否安裝成功 三、tcping 工具簡單使用方法 一、tcping 命令簡介 tcping 的主要功能…

智慧化工園區安全風險管控平臺建設方案(Word)

1 項目概況 1.1 園區概況 1.1.1 XX化工園區簡況 1.1.2 企業現狀 1.1.3 園區發展方向 1.1.4 園區信息化現狀 1.2 項目建設背景 1.2.1 政策背景 1.3 項目建設需求分析 1.3.1 政策需求分析 1.3.2 安全生產監管需求分析 1.3.3 應急協同管理需求分析 1.3.4 工業互聯網安…

【動手學深度學習】2.3. 線性代數

目錄 2.3. 線性代數1&#xff09;標量2&#xff09;向量3&#xff09;矩陣4&#xff09;張量5&#xff09;張量的基本性質6&#xff09;降維7&#xff09;點積8&#xff09;矩陣-向量積9&#xff09;矩陣-矩陣乘法10&#xff09;范數11&#xff09; 小結 2.3. 線性代數 本節將…

如何在項目當中使用redis進行范圍搜索

目錄 如何將地理位置數據保存到 Redis 中以支持范圍查詢 Redis 中的 GEO 類型是什么&#xff1f; 如何保存 GEO 數據到 Redis 分段解釋&#xff1a; RedisKey.POSTS_ANIMALS_LOCATIONS new Point(longitude, latitude) 如何進行范圍搜索 Redis GEO 范圍搜索核心語句 1…

物聯網低功耗保活協同優化方案:軟硬件與WiFi網關動態聯動

目錄 一、總體方案概述 二、架構組成 2.1 系統拓撲 2.2 硬件端(MCU + WiFi 模組) 2.3 WiFi 網關 2.4 云端服務器 三、低功耗保活技術設計模式 3.1 模式一:定時喚醒 + MQTT 保活 3.1.1 設備端 3.1.2 優勢 3.2 模式二:網關保活代理 + 本地網絡喚醒 3.2.1 網關功能…

UniApp+Vue3微信小程序二維碼生成、轉圖片、截圖保存整頁

二維碼生成工具使用uqrcode/js&#xff0c;版本4.0.7 官網地址&#xff1a;uQRCode 中文文檔&#xff08;不建議看可能會被誤導&#xff09; 本項目采用了npm引入方式&#xff0c;也可通過插件市場引入&#xff0c;使用上會略有不同 準備工作&#xff1a; 安裝&#xff1a;pnpm…

Zenmap代理情況下無法掃描ip

原因是開了代理會報錯 error “only ethernet devices can be used for raw scans on Windows” 在掃描參數后加 -sT -Pn&#xff0c;但會導致結果太多 例如&#xff1a;nmap -sT -T4 -A -v -Pn 10.44.2.0/24 如果你只是想找沒人用的IP&#xff0c;你不需要搞復雜的原始層掃描&…

將多個值關聯到同一個 key的map(key可以重復的map)示例

在 Java 中&#xff0c;標準的 Map 接口要求 key 必須唯一&#xff0c;如果需要 key 可重復 且保持 插入順序 的數據結構&#xff0c;可以使用以下方案&#xff1a; 1. 使用 List<Map.Entry<K, V>> 最直接的方式是用鏈表存儲鍵值對&#xff0c;允許重復 key&…

Arthas(阿爾薩斯)

一、Arthas 是什么&#xff1f; Arthas&#xff08;阿爾薩斯&#xff09;是阿里巴巴開源的一款 Java 在線診斷工具&#xff0c;基于 Java Agent 和字節碼增強技術實現。它無需重啟 JVM&#xff0c;即可動態追蹤代碼執行、實時查看 JVM 狀態、修改代碼邏輯&#xff0c;是生產環…

深入解讀Qwen3技術報告(三):深入剖析Qwen3模型架構

重磅推薦專欄&#xff1a; 《大模型AIGC》 《課程大綱》 《知識星球》 本專欄致力于探索和討論當今最前沿的技術趨勢和應用領域&#xff0c;包括但不限于ChatGPT和Stable Diffusion等。我們將深入研究大型模型的開發和應用&#xff0c;以及與之相關的人工智能生成內容&#xff…

UE4游戲查找本地角色數據的方法-SDK

UE4中&#xff0c;玩家的表示通常涉及以下幾個類&#xff1a; APlayerController: 代表玩家的控制邏輯&#xff0c;處理輸入等。 APawn: 代表玩家在世界中的實體&#xff08;比如一個角色、一輛車&#xff09;。APlayerController 控制一個 APawn。 ACharacter: APawn 的一個…

springboot+vue實現服裝商城系統(帶用戶協同過濾個性化推薦算法)

今天教大家如何設計一個服裝商城 , 基于目前主流的技術&#xff1a;前端vue3&#xff0c;后端springboot。 同時還帶來的項目的部署教程。 系統最大的亮點是使用了兩個推薦算法: 1. 基于Jaccard算法的用戶瀏覽歷史推薦。 2. 基于用戶的協同過濾算法個性化推薦。 還有核心的商…

ERROR: Could not install packages due to an OSError: [WinError 5] 拒絕訪問

有可能是設置了代理 unset ALLPROXY 或者注釋掉 當然也有可能是其他原因 權限不足?? 以管理員身份運行 CMD/PowerShell&#xff0c;或使用 --user 安裝 ??文件被占用?? 關閉殺毒軟件或重啟電腦 Python 環境損壞?? 重新安裝 Python 或使用虛擬環境 ?? 殺毒軟件阻止…

【深尚想!愛普特APT32F1023H8S6單片機重構智能電機控制新標桿】

在智能家電與健康器械市場爆發的今天&#xff0c;核心驅動技術正成為產品突圍的關鍵。傳統電機控制方案面臨集成度低、開發周期長、性能瓶頸三大痛點&#xff0c;而愛普特電子帶來的APT32F1023H8S6單片機無感三合一方案&#xff0c;正在掀起一場智能電機控制的技術革命。 爆款基…

一個.NET開源、輕量級的運行耗時統計庫

前言 在.NET開發中&#xff0c;為了準確統計對應方法的執行時間&#xff0c;我們最常用的方式是手動使用 Stopwatch 來顯式編寫計時邏輯&#xff0c;但是假如你需要大量的使用 Stopwatch 來進行耗時統計的話不利于保持代碼的整潔和增加代碼的維護成本。 項目介紹 MethodTime…

嵌入式鴻蒙openharmony應用開發環境搭建與工程創建實現

各位小伙伴大家好,本周開始分享鴻蒙開發相關的內容,從基礎的配置方法到各種功能的實現,探索國產操作系統的奧秘。 第一:觀察結果 第二:開源語言 ArkTS是鴻蒙應用開發中使用的TypeScript超集,提供了一套豐富的API來構建應用界面和邏輯。 第三:環境搭建 步驟 1 通過如…

軟考 組合設計模式

組合設計模式&#xff08;Composite Pattern&#xff09;是結構型設計模式之一&#xff0c;它的核心思想是將對象組合成樹形結構來表示“部分-整體”的層次結構&#xff0c;使得用戶對單個對象和組合對象的使用具有一致性。 主要概念&#xff1a; 組件&#xff08;Component&a…

vue 中的v-once

&#x1f530; 基礎理解 ? 語法&#xff1a; <span v-once>{{ msg }}</span>? 效果&#xff1a; ? 只渲染一次&#xff0c;之后無論數據如何變化&#xff0c;該內容都不會更新。 ? 非常適用于靜態內容或首次加載后不需要變化的數據。&#x1f9ea; 示例&…

GPU訓練和call方法

知識點回歸: CPU性能的查看:看架構代際、核心數、線程數GPU性能的查看:看顯存、看級別、看架構代際GPU訓練的方法:數據和模型移動到GPU device上類的call方法:為什么定義前向傳播時可以直接寫作self.fc1(x)import torch import torch.nn as nn import torch.optim as opti…

人臉識別備案開啟安全防護模式!緊跟《辦法》!

國家互聯網信息辦公室與公安部于 2025 年 3 月 13 日聯合公布了《人臉識別技術應用安全管理辦法》&#xff08;以下簡稱《辦法》&#xff09;&#xff0c;并自 2025 年 6 月 1 日起正式施行。其中&#xff0c;人臉識別備案成為了規范技術應用、守護信息安全的關鍵一環。? 一、…