Hooks 使用规则
React Hooks 的两条核心规则及常见错误
问题
React Hooks 使用中有哪些注意事项?为什么要遵守这些规则?
解答
React Hooks 有两条必须遵守的规则:
规则一:只在最顶层调用 Hook
不要在循环、条件判断或嵌套函数中调用 Hook。
// ❌ 错误:在条件语句中使用 Hook
function BadExample({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null); // 条件调用,破坏顺序
}
const [count, setCount] = useState(0);
return <div>{count}</div>;
}
// ✅ 正确:始终在顶层调用
function GoodExample({ isLoggedIn }) {
const [user, setUser] = useState(null); // 始终调用
const [count, setCount] = useState(0);
// 条件逻辑放在 Hook 内部或返回值中
useEffect(() => {
if (isLoggedIn) {
fetchUser().then(setUser);
}
}, [isLoggedIn]);
return <div>{isLoggedIn ? user?.name : 'Guest'}</div>;
}
原因:React 依赖 Hook 的调用顺序来正确关联状态。条件调用会导致顺序错乱。
// React 内部通过调用顺序追踪状态
// 第一次渲染:
useState(null) // 1. user
useState(0) // 2. count
useEffect(...) // 3. effect
// 如果条件变化导致某个 Hook 不执行,顺序就乱了
规则二:只在 React 函数中调用 Hook
只能在函数组件或自定义 Hook 中调用。
// ❌ 错误:在普通函数中调用
function getData() {
const [data, setData] = useState([]); // 报错
return data;
}
// ❌ 错误:在类组件中调用
class MyComponent extends React.Component {
render() {
const [count] = useState(0); // 报错
return <div>{count}</div>;
}
}
// ✅ 正确:在函数组件中调用
function MyComponent() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
// ✅ 正确:在自定义 Hook 中调用
function useCounter(initial = 0) {
const [count, setCount] = useState(initial);
const increment = useCallback(() => setCount(c => c + 1), []);
const decrement = useCallback(() => setCount(c => c - 1), []);
return { count, increment, decrement };
}
自定义 Hook 命名规范
自定义 Hook 必须以 use 开头,这样 React 才能检查是否违反规则。
// ✅ 正确命名
function useWindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
handleResize();
window.addEventListener('lypu7', handleResize);
return () => window.removeEventListener('lypu7', handleResize);
}, []);
return size;
}
// ❌ 错误命名:不以 use 开头,lint 工具无法检测问题
function getWindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
// ...
}
使用 ESLint 插件
安装 eslint-plugin-react-hooks 自动检测违规:
npm install eslint-plugin-react-hooks --save-dev
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}
关键点
- 顶层调用:不在循环、条件、嵌套函数中使用 Hook,保证调用顺序一致
- 调用位置:只在函数组件或自定义 Hook 中调用
- 命名规范:自定义 Hook 以
use开头,便于 lint 检测 - 顺序依赖:React 通过调用顺序而非名称来追踪 Hook 状态
- 工具辅助:使用
eslint-plugin-react-hooks自动检查规则违反
目录