React Hooks 与 Hooks 规则 – 我最终恍然大悟的理解
Source: Dev.to

今天,有些东西终于对我恍然大悟了。
我已经使用React Hooks 很久了,但说实话,我并没有真正理解它们是什么,为什么 React 对它们的规则如此严格,以及为什么一些看似可行的模式仍被视为不好的实践。
这篇博客是我尝试把我个人理解写下来的过程,以便:
- 如果我在一两周后再次阅读这篇文章
- 或者将来我感到困惑时
这篇文章能把我拉回到完全清晰的状态,而不仅仅是表面的了解。
什么是 React Hooks
第一个被澄清的误解是:
Hooks 不只是普通的辅助函数。
Hooks 是 React 提供的特殊构建函数,直接与 React 的 Fiber 架构 交互。
Hooks 用于:
- 向 React 注册状态
- 注册副作用
- 将组件逻辑连接到 React 的内部更新系统
这就是为什么:
- 每个 hook 都以
use开头(useState、useEffect、useRef等) - React 不会把 hooks 当作普通的 JavaScript 函数来处理——它们与 React 渲染和更新组件的方式紧密耦合。
Hook 与 React Fiber —— 缺失的思维模型
在内部,React 维护着一个 Fiber Tree。对于每一次组件渲染,React 会将 hook 存储在一个 linked list 中:
- 第一次 hook 调用成为第一个节点
- 第二次 hook 调用成为第二个节点
- ……以此类推
React 不通过名称来识别 hook;它通过 顺序 来识别。这一点就解释了 所有 Hook 规则。
React Hooks 概览
React 提供了许多 Hook,但实际使用中最常见的分组是:
最常用的 Hook
useStateuseEffectuseReduceruseContext
性能 / 优化 Hook
useRefuseCallbackuseMemouseTransitionuseDeferredValue
低层或高级 Hook
useSyncExternalStoreuseInsertionEffect
不同的 Hook 目的各异——但 所有 Hook 都遵循相同的规则。
Hooks 规则(终于说通了的那部分)
✅ 规则 1:只在 顶层 调用 Hook
- 不要在
if语句内部使用 Hook - 不要在循环内部使用 Hook
- 不要在
return之后使用 Hook
Hook 绝不能有条件地执行。
错误示例
if (imdbRating > 8) {
const [isTop, setIsTop] = useState(true);
}
为什么危险:该 Hook 可能在某些渲染中执行,而在其他渲染中不执行,导致 Hook 顺序被打乱,React 无法正确匹配状态。
✅ 规则 2:只从 React 函数中调用 Hook
Hook 只能在以下位置使用:
- 函数组件
- 自定义 Hook
它们 不能在普通的 JavaScript 函数中调用,因为 React 只在渲染阶段跟踪 Hook。
“这段代码能运行… 那它为什么仍然是错的?”
派生状态陷阱
我曾经以为这样写没问题:
const [isTop, setIsTop] = useState(imdbRating > 8);
useEffect(() => {
setIsTop(imdbRating > 8);
}, [imdbRating]);
代码可以正常运行,但在概念上它创建了不必要的状态,导致糟糕的设计。
正确的思考方式:派生,而不是存储
如果一个值可以完全从 props 或其他状态中派生出来,不要把它存成独立的状态。
const isTop = imdbRating > 8;
没有额外的状态,没有 effect,也没有额外的重新渲染——从而得到更简洁的逻辑和更少的 bug。
理解使用平均评分的状态更新
当新状态依赖于先前的状态时,使用 函数式更新:
// Direct update
setAvgRating(Number(imdbRating));
// Functional update (depends on previous value)
setAvgRating(prev => (prev + userRating) / 2);
React 同时支持直接更新和函数式更新。函数式更新可以避免:
- 过时的值
- 由于批处理导致的意外行为
我现在如何可视化 Hooks
- Hooks = 链表中的节点
- React = 该链表的管理者
- 改变顺序 = ❌ 系统崩溃
因此,hooks 必须 在每次渲染时以相同的顺序调用,且不能有条件。
最终实现
- 不是随意的
- 不是“React 无缘无故地严格”
它们是 React 内部设计的直接结果。一旦我理解了 Fiber 和 Hook 的顺序,我就不需要记忆这些规则——它们开始变得合乎逻辑。
Final Thought
如果你在使用 React Hooks 时感到困难:
- 不要只学习如何使用它们——要了解它们存在的 原因。
当“原因”清晰时:
- 代码更简洁
- Bug 更少
- 信心提升
这篇博客也是写给未来的自己的——这样这种困惑就不会再出现。