为何Hooks要依赖于调用顺序
面试速答
- Hooks 依赖调用顺序,不是“官方硬规定”,而是 实现模型决定的。
- React 在执行函数组件时,需要按顺序把每个 Hook 调用映射到内部状态链表或槽位。
- 一旦顺序变化,后面的状态、effect、ref 全都会对错位置。
用极简模型理解
假设组件里有两个 Hook:
function Demo() {
const [count] = useState(0)
const [name] = useState('Tom')
}
React 可以把它粗略理解成:
hookStates[0] -> count
hookStates[1] -> name
下一次 render 时,只要还是这个顺序,React 就能正确取回它们。
一旦条件分支介入会怎样
function Demo({visible}: {visible: boolean}) {
const [count] = useState(0)
if (visible) {
useEffect(() => {}, [])
}
const [name] = useState('Tom')
}
当 visible 从 true 变成 false 时,第二个 Hook 的位置就变了:
- 原来第 2 个位置是
useEffect - 现在第 2 个位置变成
useState(name)
后续整个映射都会错位。
为什么 React 不用名字定位
因为 Hook 是普通函数调用,不像 class 的 this.state.xxx 那样天然有名字锚点。
React 选择“按调用顺序记录”的方案,换来的是:
- API 足够简洁
- 自定义 Hook 易于组合
- 内部实现统一
代价就是调用顺序必须稳定。
标准答法
问:为什么 Hooks 必须依赖调用顺序?
答:因为 React 在函数组件执行时,是按顺序记录和读取每个 Hook 的内部状态节点的。只有顺序稳定,React 才知道当前这次 useState 对应上次的哪一个状态。
易错点
- 只会背“不能放条件里”,解释不出为什么。
- 以为 React 能通过变量名判断 Hook 身份。
- 不理解自定义 Hook 也是靠调用顺序展开的。
速记要点
- Hook 没有名字索引,靠顺序定位。
- 条件、循环会破坏顺序。
- 这就是 Hooks 规则的底层原因。