Hooks(useState、useEffect 等)有两条规则:
- 只在最顶层调用 Hooks — 不要在条件、循环或嵌套函数中调用。
- 只在 React 函数中调用 Hooks — 组件或其他自定义 Hooks。
jsx
function Profile({ id }) {
const [user, setUser] = useState(null); // ✅ top level
if (id) {
const [x] = useState(0); // ❌ conditional hook — breaks React
}
}
为什么这很重要
React 不是根据名称来识别 Hooks — 它依赖于调用顺序。在每次渲染时,它都会按照完全相同的顺序遍历 Hooks,并将每个调用与内部列表中的一个插槽相匹配:
text
Render 1: useState(A) → slot 0, useState(B) → slot 1, useEffect → slot 2
Render 2: useState(A) → slot 0, useState(B) → slot 1, useEffect → slot 2
如果你有条件地调用 Hook,顺序可能会在渲染之间改变。那么插槽 1 可能在一次渲染中是 useState(B),在下一次渲染中是 useEffect — React 会将错误的状态传递给错误的 Hook,破坏一切。
如何正确编写条件逻辑
保持 Hook 无条件,将条件放在里面,或根据它返回的值进行分支:
jsx
const [user, setUser] = useState(null);
useEffect(() => {
if (!id) return; // condition INSIDE the effect, not around it
fetchUser(id).then(setUser);
}, [id]);
eslint-plugin-react-hooks 链接规则会自动强制执行这些规则。
