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为什么能切换
    • React 更新系统的“回路闭合点”
    • 为什么hooks不能写在条件里
    • 为啥hooks要用全局变量(而不是参数传递)
    • React的hooks需要知道的问题
      • 🔥 React Hooks 深挖题(附考察点)
      • 一、底层原理类(核心区分题)
        • 1️⃣ 为什么 Hooks 不能写在 if 里?
        • 追问:
        • 真正考察:
        • 2️⃣ useEffect 的依赖数组是怎么比较的?
        • 追问:
        • 3️⃣ 为什么严格模式下 effect 执行两次?
      • 二、闭包 & 状态陷阱类
        • 4️⃣ 为什么下面代码打印的是 0?
        • 5️⃣ 如何彻底解决闭包问题?
      • 三、并发模型类
        • 6️⃣ useTransition 本质解决了什么问题?
        • 7️⃣ useDeferredValue 和 useMemo 的本质区别?
        • 8️⃣ 在并发模式下 useEffect 可能不执行吗?
      • 四、性能优化类
        • 9️⃣ 为什么 useCallback 有时候会让性能更差?
        • 🔟 如何避免 Context 全量刷新?
      • 五、源码级问题(能讲出来基本是架构级)
        • 1️⃣1️⃣ 请简述 useState 内部实现
        • 1️⃣2️⃣ React 如何实现批量更新?
      • 六、真实架构场景题(AI Chat / 大型系统)
        • 1️⃣3️⃣ 你如何设计一个可中断的流式输出 Hook?
        • 1️⃣4️⃣ 如果 2000 条消息,如何避免重渲染卡死?
      • 七、极限思维题(区分架构师)
        • 1️⃣5️⃣ 如果让你实现一个简版 Hooks 系统,你会怎么设计?
        • 1️⃣6️⃣ 为什么 Hooks 比 class 更适合并发模式?
      • 八、死亡连环追问(终极)
        • 1️⃣7️⃣ 为什么 React 不采用 Vue 那种响应式?
        • 1️⃣8️⃣ 你如何判断一个 Hook 设计是否优雅?
      • 九、真正压轴问题
        • 1️⃣9️⃣ 为什么 React 要区分 render 阶段和 commit 阶段?
        • 2️⃣0️⃣ 如果一个 effect 触发 setState,会发生什么?
      • 🎯 如果你真准备大厂高级面试
  • react全家桶

  • 《React18》学习笔记
  • react原理
mamingjuan
2026-01-01
目录

React的hooks需要知道的问题

# 🔥 React Hooks 深挖题(附考察点)

基于 React 18 并发模型。


# 一、底层原理类(核心区分题)

# 1️⃣ 为什么 Hooks 不能写在 if 里?

# 追问:

  • React 如何知道当前 useState 对应哪个 state?
  • 如果少执行一个 hook,会发生什么?
  • Fiber 中 hooks 是数组还是链表?为什么?

# 真正考察:

  • Fiber 结构
  • hook 单向链表
  • memoizedState 指针移动机制
  • mount vs update dispatcher

如果候选人能讲出:

fiber.memoizedState -> hook1 -> hook2 -> hook3
1

基本就是高阶选手。


# 2️⃣ useEffect 的依赖数组是怎么比较的?

# 追问:

  • 是深比较还是浅比较?
  • 为什么对象经常导致死循环?
  • React 内部如何存 deps?

真正答案:

  • Object.is 浅比较
  • 上一次 deps 存在 hook.memoizedState
  • updateEffect 时逐个比较

# 3️⃣ 为什么严格模式下 effect 执行两次?

不是简单回答“开发模式检测”。

追问:

  • 是 render 两次还是 effect 两次?
  • cleanup 什么时候执行?
  • 生产环境是否会?

考察:

  • mount → destroy → mount 流程模拟
  • 副作用幂等性设计能力

# 二、闭包 & 状态陷阱类

# 4️⃣ 为什么下面代码打印的是 0?

useEffect(() => {
  setInterval(() => {
    console.log(count)
  }, 1000)
}, [])
1
2
3
4
5

追问:

  • React 是不是“响应式”?
  • 这是不是 React 的 bug?
  • 如何设计一个稳定的 useInterval?

高级答案必须提到:

  • render 阶段形成闭包
  • state 存在 fiber
  • effect 捕获的是旧变量

# 5️⃣ 如何彻底解决闭包问题?

说出三种:

  1. 函数式更新
  2. useRef 保存最新值
  3. useEvent(实验 API)

能讲到 useEvent 的是加分项。


# 三、并发模型类

# 6️⃣ useTransition 本质解决了什么问题?

不是回答“防卡顿”。

追问:

  • 它如何改变 update 优先级?
  • React 内部如何标记 transition?
  • 会不会丢帧?

考察:

  • lane 模型
  • 调度优先级
  • 可中断渲染

# 7️⃣ useDeferredValue 和 useMemo 的本质区别?

很多人会说“一个缓存,一个延迟”。

真正差别:

  • useMemo 是 render 阶段缓存
  • useDeferredValue 是调度层降级优先级

# 8️⃣ 在并发模式下 useEffect 可能不执行吗?

答案:可能。

追问:

  • 哪种情况下?
  • render 被打断会发生什么?
  • commit 才会触发 effect

# 四、性能优化类

# 9️⃣ 为什么 useCallback 有时候会让性能更差?

高级回答:

  • 额外 hook 记录
  • deps 比较成本
  • 子组件未 memo 毫无意义
  • GC 压力

# 🔟 如何避免 Context 全量刷新?

考察真实架构能力。

优秀回答:

  • context 拆分
  • useContextSelector
  • 外部状态库(zustand / jotai)
  • selector 模式

# 五、源码级问题(能讲出来基本是架构级)

# 1️⃣1️⃣ 请简述 useState 内部实现

必须提到:

hook = {
  memoizedState,
  queue: { pending },
  next
}
1
2
3
4
5

dispatch 触发 scheduleUpdateOnFiber


# 1️⃣2️⃣ React 如何实现批量更新?

React 并不是通过简单的计时器实现的,而是通过 优先级 和 任务队列。

追问:

  • React 17 和 18 区别?
  • 为什么 setTimeout 里以前不批处理?
特性 React 17 React 18
批量更新范围 仅限生命周期和合成事件。 全面自动批处理(包括 Promise, setTimeout, 原生事件)。
渲染模式 同步、不可中断的渲染。 并发渲染 (Concurrent Rendering),可中断、可切片。
主要 API ReactDOM.render ReactDOM.createRoot (必须使用新 API 开启新特性)。
新功能 无。 引入 useTransition, useDeferredValue 处理非紧急更新。
Suspense 仅支持代码分割。 支持服务端渲染 (SSR) 和数据获取。

为什么 React 17(及以前)在 setTimeout 中不批处理?

这背后的根本原因在于 执行上下文(Execution Context) 的丢失。

核心机制:同步的“开关”

在 React 17 中,批量更新是基于 合成事件系统(Synthetic Event System) 实现的。

  • 当用户点击按钮时,React 会先将一个内部标志(如 isBatchingUpdates)设为 true。
  • 接着执行你的 onClick 函数。
  • 函数执行完,React 把标志设回 false,并触发一次重新渲染。

为什么 setTimeout 会“逃逸”?

当你的代码里写了 setTimeout,执行顺序如下:

  1. React 进入点击事件处理,开启“批量模式”。
  2. 遇到 setTimeout,里面的回调函数被推入浏览器的 事件队列(Event Queue) 异步等待。
  3. onClick 同步代码运行结束,React 关闭了批量模式并完成渲染。
  4. 很久以后,setTimeout 里的回调触发,此时 React 的批量开关已经关掉了。
  5. 每调用一次 setState,React 发现不在批量模式中,只好被迫立即进行一次完整的渲染流程。

# 六、真实架构场景题(AI Chat / 大型系统)

# 1️⃣3️⃣ 你如何设计一个可中断的流式输出 Hook?

场景:AI Chat

要求:

  • 支持流式数据
  • 支持 stop
  • 支持重新生成
  • 防止内存泄漏

看他是否提到:

  • AbortController
  • ref 保存 controller
  • effect cleanup
  • transition 优化 UI

# 1️⃣4️⃣ 如果 2000 条消息,如何避免重渲染卡死?

优秀回答:

  • 状态拆分
  • useTransition
  • 虚拟列表
  • key 稳定
  • memo 分层

# 七、极限思维题(区分架构师)

# 1️⃣5️⃣ 如果让你实现一个简版 Hooks 系统,你会怎么设计?

考察:

  • 全局指针 currentHook
  • 数组 or 链表
  • render 重置 index

# 1️⃣6️⃣ 为什么 Hooks 比 class 更适合并发模式?

关键点:

  • 无 this
  • 无生命周期耦合
  • 副作用统一在 commit 阶段

# 八、死亡连环追问(终极)


# 1️⃣7️⃣ 为什么 React 不采用 Vue 那种响应式?

对比:

  • Vue 依赖收集
  • React 显式依赖数组
  • 调度控制权差异

涉及对 Vue.js 的理解。


# 1️⃣8️⃣ 你如何判断一个 Hook 设计是否优雅?

标准:

  • 依赖最小化
  • 不泄漏内部实现
  • 副作用可控
  • 并发安全
  • 可组合

# 九、真正压轴问题


# 1️⃣9️⃣ 为什么 React 要区分 render 阶段和 commit 阶段?

如果他说:

因为要支持中断

那是初级回答。

高级回答必须提到:

  • 可预测性
  • 副作用隔离
  • 并发安全
  • 时间切片

# 2️⃣0️⃣ 如果一个 effect 触发 setState,会发生什么?

追问:

  • 会不会死循环?
  • 如何避免?
  • React 内部如何防止无限 update?

# 🎯 如果你真准备大厂高级面试

我建议你至少能:

  • 手写简版 useState
  • 讲清 fiber hooks 链表
  • 解释 lane 优先级
  • 讲清闭包本质
  • 解释并发打断
上次更新: 2026/03/04, 09:44:50
为啥hooks要用全局变量(而不是参数传递)
react全家桶概览

← 为啥hooks要用全局变量(而不是参数传递) react全家桶概览→

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