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
2
3
4
5
追问:
- React 是不是“响应式”?
- 这是不是 React 的 bug?
- 如何设计一个稳定的 useInterval?
高级答案必须提到:
- render 阶段形成闭包
- state 存在 fiber
- effect 捕获的是旧变量
# 5️⃣ 如何彻底解决闭包问题?
说出三种:
- 函数式更新
- useRef 保存最新值
- 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
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,执行顺序如下:
- React 进入点击事件处理,开启“批量模式”。
- 遇到
setTimeout,里面的回调函数被推入浏览器的 事件队列(Event Queue) 异步等待。 onClick同步代码运行结束,React 关闭了批量模式并完成渲染。- 很久以后,
setTimeout里的回调触发,此时 React 的批量开关已经关掉了。 - 每调用一次
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