
规则:rules-of-hooks
ReactAPI 参考:ESLint 插件
规则:rules-of-hooks
校验组件和 hooks 是否遵循 Hooks 规则。
规则详情
React 依赖 hooks 的调用顺序来在渲染之间正确保留状态。每次你的组件渲染时,React 期望以完全相同的顺序调用完全相同的 hooks。当 hooks 被条件调用或在循环中调用时,React 会失去与每个 hook 调用对应的状态,导致状态错位和“渲染的 hooks 少于/多于预期”等错误。
常见违规
这些模式违反了 Hooks 规则:
- 条件中的 hooks(
if/else、三元运算符、&&/||) - 循环中的 hooks(
for、while、do-while) - 提前 return 之后的 hooks
- 回调/事件处理器中的 hooks
- 异步函数中的 hooks
- 类方法中的 hooks
- 模块级别的 hooks
注意:
usehook
usehook 与其他 React hooks 不同。你可以在条件和循环中调用它:
js// ✅ `use` can be conditional if (shouldFetch) { const data = use(fetchPromise); } // ✅ `use` can be in loops for (const promise of promises) { results.push(use(promise)); }然而,
use仍然有限制:
- 不能包裹在 try/catch 中
- 必须在组件或 hook 内部调用
了解更多:
useAPI 参考
无效
此规则的不正确代码示例:
js
// ❌ Hook in condition
if (isLoggedIn) {
const [user, setUser] = useState(null);
}
// ❌ Hook after early return
if (!data) return <Loading />;
const [processed, setProcessed] = useState(data);
// ❌ Hook in callback
<button onClick={() => {
const [clicked, setClicked] = useState(false);
}}/>
// ❌ `use` in try/catch
try {
const data = use(promise);
} catch (e) {
// error handling
}
// ❌ Hook at module level
const globalState = useState(0); // Outside component
有效
此规则的正确代码示例:
js
function Component({ isSpecial, shouldFetch, fetchPromise }) {
// ✅ Hooks at top level
const [count, setCount] = useState(0);
const [name, setName] = useState('');
if (!isSpecial) {
return null;
}
if (shouldFetch) {
// ✅ `use` can be conditional
const data = use(fetchPromise);
return <div>{data}</div>;
}
return <div>{name}: {count}</div>;
}
故障排查
我想基于某些条件获取数据
你试图有条件地调用 useEffect:
js
// ❌ Conditional hook
if (isLoggedIn) {
useEffect(() => {
fetchUserData();
}, []);
}
无条件地调用 hook,在内部检查条件:
js
// ✅ Condition inside hook
useEffect(() => {
if (isLoggedIn) {
fetchUserData();
}
}, [isLoggedIn]);
注意:
有比使用 useEffect 更好的方法来获取数据。考虑使用 TanStack Query、useSWR 或者 React Router(v6.4 版本及以上)来获取数据。这些解决方案处理了重复请求、对响应进行缓存并且会避免网络瀑布。
了解更多:获取数据
我需要针对不同场景使用不同状态
你试图有条件地初始化 state:
js
// ❌ Conditional state
if (userType === 'admin') {
const [permissions, setPermissions] = useState(adminPerms);
} else {
const [permissions, setPermissions] = useState(userPerms);
}
始终调用 useState,有条件地设置初始值:
js
// ✅ Conditional initial value
const [permissions, setPermissions] = useState(
userType === 'admin' ? adminPerms : userPerms
);
选项
你可以使用共享的 ESLint 设置来配置自定义 effect hooks(在 eslint-plugin-react-hooks 6.1.1 及更高版本中可用):
js
{
"settings": {
"react-hooks": {
"additionalEffectHooks": "(useMyEffect|useCustomEffect)"
}
}
}
additionalEffectHooks:匹配应被视为 effects 的自定义 hooks 的正则表达式模式。这允许useEffectEvent和类似的事件函数从你的自定义 effect hooks 中调用。
此共享配置同时被 rules-of-hooks 和 exhaustive-deps 规则使用,确保所有 hooks 相关的 lint 行为一致。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
