验证组件和钩子是否遵循 Hooks 规则。
🌐 Validates that components and hooks follow the Rules of Hooks.
规则详情
🌐 Rule Details
React 依赖于钩子调用的顺序来在渲染之间正确地保持状态。每次组件渲染时,React 都期望以完全相同的顺序调用完全相同的钩子。当钩子在条件语句或循环中被调用时,React 会失去对哪个状态对应于哪个钩子调用的追踪,从而导致状态不匹配以及“渲染的钩子数量少于/多于预期”之类的错误。
🌐 React relies on the order in which hooks are called to correctly preserve state between renders. Each time your component renders, React expects the exact same hooks to be called in the exact same order. When hooks are called conditionally or in loops, React loses track of which state corresponds to which hook call, leading to bugs like state mismatches and “Rendered fewer/more hooks than expected” errors.
常见违规
🌐 Common Violations
这些模式违反了钩子规则:
🌐 These patterns violate the Rules of Hooks:
- 条件中的 Hooks (
if/else,三元,&&/||) - 循环中的钩子 (
for,while,do-while) - 在早期返回之后使用钩子
- 回调/事件处理程序中的钩子
- 异步函数中的钩子
- 类方法中的钩子
- 模块级别的钩子
无效
🌐 Invalid
此规则的错误代码示例:
🌐 Examples of incorrect code for this rule:
// ❌ 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有效
🌐 Valid
此规则的正确代码示例:
🌐 Examples of correct code for this rule:
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>;
}故障排除
🌐 Troubleshooting
我想要根据某些条件获取数据
🌐 I want to fetch data based on some condition
你正在尝试有条件地调用 useEffect:
🌐 You’re trying to conditionally call useEffect:
// ❌ Conditional hook
if (isLoggedIn) {
useEffect(() => {
fetchUserData();
}, []);
}无条件调用钩子,并检查内部条件:
🌐 Call the hook unconditionally, check condition inside:
// ✅ Condition inside hook
useEffect(() => {
if (isLoggedIn) {
fetchUserData();
}
}, [isLoggedIn]);我需要针对不同场景使用不同的状态
🌐 I need different state for different scenarios
你正在尝试有条件地初始化状态:
🌐 You’re trying to conditionally initialize state:
// ❌ Conditional state
if (userType === 'admin') {
const [permissions, setPermissions] = useState(adminPerms);
} else {
const [permissions, setPermissions] = useState(userPerms);
}始终调用 useState,并有条件地设置初始值:
🌐 Always call useState, conditionally set the initial value:
// ✅ Conditional initial value
const [permissions, setPermissions] = useState(
userType === 'admin' ? adminPerms : userPerms
);选项
🌐 Options
你可以使用共享的 ESLint 设置配置自定义 effect 钩子(在 eslint-plugin-react-hooks 6.1.1 及更高版本中可用):
🌐 You can configure custom effect hooks using shared ESLint settings (available in eslint-plugin-react-hooks 6.1.1 and later):
{
"settings": {
"react-hooks": {
"additionalEffectHooks": "(useMyEffect|useCustomEffect)"
}
}
}additionalEffectHooks:正则表达式模式匹配应被视为效果的自定义钩子。这允许从你的自定义效果钩子中调用useEffectEvent及类似的事件函数。
这个共享配置被 rules-of-hooks 和 exhaustive-deps 规则使用,确保所有与钩子相关的代码检查行为一致。
🌐 This shared configuration is used by both rules-of-hooks and exhaustive-deps rules, ensuring consistent behavior across all hook-related linting.