Glittering's blog Glittering's blog
Home
  • 学习手册

    • 《TypeScript教程》
    • 《Git》
    • 《Vite》
    • 《Vue3》
    • 《React18》
    • 《CSS》
    • 《Tailwind CSS》
    • 《JavaScript教程》
    • 《ES6 教程》
    • 《TypeScript 从零实现 axios》
  • 技术文档
  • 算法
  • 工作总结
  • 实用技巧
  • collect
About
  • Classification
  • Label
GitHub (opens new window)

Glitz Ma

前端开发工程师
Home
  • 学习手册

    • 《TypeScript教程》
    • 《Git》
    • 《Vite》
    • 《Vue3》
    • 《React18》
    • 《CSS》
    • 《Tailwind CSS》
    • 《JavaScript教程》
    • 《ES6 教程》
    • 《TypeScript 从零实现 axios》
  • 技术文档
  • 算法
  • 工作总结
  • 实用技巧
  • collect
About
  • Classification
  • Label
GitHub (opens new window)
  • react基础

  • react原理

    • Vue3 effect vs react hooks
    • Fiber是什么
    • renderWithHooks是怎么挂到Fiber
    • mount/update为什么能切换
      • 一、Hooks Dispatcher 是什么?
        • 本质一句话
      • 二、Dispatcher 在哪里被切换?
        • renderWithHooks 的关键判断
        • current 是谁?
        • 结论
      • 三、为什么不能用 Fiber.tag 判断?
      • 四、mount / update 两套逻辑差在哪?
        • 1️⃣ mountState:创建 Hook
        • mount 的核心任务
        • 2️⃣ updateState:复用 Hook
        • update 的核心任务
        • 3️⃣ 两者最本质的差异
      • 五、Hooks 顺序为什么不能变?(根因)
        • render 期间:
        • update 阶段:
      • 六、StrictMode 下为什么会“执行两次 mount”?
        • React 18 开发模式:
      • 七、和 Vue effect 的根本不同
      • 八、终极一句话总结
    • React 更新系统的“回路闭合点”
    • 为什么hooks不能写在条件里
    • 为啥hooks要用全局变量(而不是参数传递)
  • react全家桶

  • 《React18》学习笔记
  • react原理
mamingjuan
2025-09-21
目录

mount/update为什么能切换

  • 先给一句话答案:
  • Hooks 能区分 mount / update,不是靠 Fiber.tag,而是靠「current Fiber 是否存在」

# 一、Hooks Dispatcher 是什么?

# 本质一句话

Hooks Dispatcher = 一组“当前 render 期间,useX 应该执行哪套实现”的函数表

const HooksDispatcherOnMount = {
  useState: mountState,
  useEffect: mountEffect,
  useMemo: mountMemo,
}

const HooksDispatcherOnUpdate = {
  useState: updateState,
  useEffect: updateEffect,
  useMemo: updateMemo,
}
1
2
3
4
5
6
7
8
9
10
11

⚠️ useState 本身只是:

export function useState(initialState) {
  return ReactCurrentDispatcher.current.useState(initialState)
}
1
2
3

👉 真正执行哪套逻辑,全看 dispatcher


# 二、Dispatcher 在哪里被切换?

答案:renderWithHooks


# renderWithHooks 的关键判断

ReactCurrentDispatcher.current =
  current === null
    ? HooksDispatcherOnMount
    : HooksDispatcherOnUpdate
1
2
3
4

# current 是谁?

  • current:上一次 commit 的 Fiber
  • workInProgress:这次 render 的 Fiber

# 结论

场景 current
首次挂载 null
后续更新 指向旧 Fiber

👉 这是 mount / update 切换的唯一条件


# 三、为什么不能用 Fiber.tag 判断?

你可能会想:

“FunctionComponent 不一直是 FunctionComponent 吗?”

原因是:

  • mount / update 是时间维度
  • Fiber.tag 是类型维度
同一个 FunctionComponent
第一次 render  → mount
第二次 render → update
1
2
3

👉 tag 根本区分不了


# 四、mount / update 两套逻辑差在哪?

我们用 useState 作为代表。


# 1️⃣ mountState:创建 Hook

function mountState(initialState) {
  const hook = mountWorkInProgressHook()

  hook.memoizedState = initialState
  hook.queue = createUpdateQueue()

  const dispatch = dispatchSetState.bind(
    null,
    currentlyRenderingFiber,
    hook.queue
  )

  return [hook.memoizedState, dispatch]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# mount 的核心任务

  • 创建 hook 节点
  • 建立 hook 链表
  • 初始化 state
  • 创建 updateQueue

# 2️⃣ updateState:复用 Hook

function updateState() {
  const hook = updateWorkInProgressHook()
  const queue = hook.queue

  let newState = hook.memoizedState

  // 处理 updateQueue
  const pending = queue.pending
  if (pending !== null) {
    // 计算新 state
  }

  hook.memoizedState = newState
  return [newState, queue.dispatch]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# update 的核心任务

  • 按顺序找到旧 hook
  • 克隆到新 Fiber
  • 执行 state 更新

# 3️⃣ 两者最本质的差异

mount update
hook 来源 新建 clone
是否读 queue ❌ ✅
是否消费 update ❌ ✅

# 五、Hooks 顺序为什么不能变?(根因)

现在你应该能自己推出来了 👇

# render 期间:

useState()   // hook #1
useEffect()  // hook #2
useMemo()    // hook #3
1
2
3

# update 阶段:

updateWorkInProgressHook()
  ↕
currentHook.next
1
2
3

👉 顺序错 = 对错 hook

if (cond) {
  useState() // ❌
}
1
2
3
  • mount 时:可能执行
  • update 时:可能不执行
  • 链表直接错位

# 六、StrictMode 下为什么会“执行两次 mount”?

这是个很好的延伸点。

# React 18 开发模式:

  • mount → unmount → mount(模拟)
  • 目的是检测副作用

⚠️ 注意:

  • Dispatcher 还是 mount
  • Fiber 被丢弃重建
  • 不会走 update

# 七、和 Vue effect 的根本不同

Vue3 React
effect 创建一次 render 可多次
依赖自动追踪 顺序隐式约定
effect ≠ render render = effect

# 八、终极一句话总结

  • Hooks Dispatcher 能切换,是因为 React 在 renderWithHooks 中,
  • 用「current Fiber 是否存在」作为时间锚点,决定 Hook 该“创建”还是“复用”
上次更新: 2026/01/21, 04:36:31
renderWithHooks是怎么挂到Fiber
React 更新系统的“回路闭合点”

← renderWithHooks是怎么挂到Fiber React 更新系统的“回路闭合点”→

Copyright © 2015-2026 Glitz Ma
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式