# Hook 规则与注意事项

URL: https://caijiao.org/react/chapter10/hook-rules
Source: docs/react/chapter10/hook-rules.md
Description: 在使用 React Hook 时，需要遵循一些规则和注意事项。了解这些规则可以帮助你避免常见的错误和性能问题，确保应用程序的稳定性和可维护性。

React Hook 是 React 16.8 引入的一项新特性，它使得函数组件能够拥有状态、生命周期方法等功能。尽管 Hook 提供了强大的功能，但它有一些必须遵守的规则。理解和遵循这些规则对于正确使用 Hook 至关重要。

## 1. Hook 的规则

### 1.1 只能在函数组件中调用 Hook

React 的 Hook 只能在函数组件内或自定义 Hook 中使用。不能在常规的 JavaScript 函数中使用 Hook。

```jsx
// 正确：在函数组件中使用 Hook
function MyComponent() {
  const [count, setCount] = useState(0);
  return <div>{count}</div>;
}

// 错误：不能在普通函数中调用 Hook
function myFunction() {
  const [count, setCount] = useState(0); // 错误
}
````

### 1.2 只能在顶层调用 Hook

为了确保 Hook 的执行顺序一致，React 要求你只能在组件的顶层调用 Hook，不能在循环、条件语句或嵌套函数中调用 Hook。

```jsx
// 正确：在组件的顶层调用 Hook
function MyComponent() {
  const [count, setCount] = useState(0);
  return <div>{count}</div>;
}

// 错误：不允许在条件语句中调用 Hook
function MyComponent() {
  if (someCondition) {
    const [count, setCount] = useState(0); // 错误
  }
}
```

### 1.3 只在 React 函数组件中使用 Hook

React Hooks 只在函数组件和自定义 Hook 中有效，不能在类组件中使用。

```jsx
// 错误：不能在类组件中使用 Hook
class MyComponent extends React.Component {
  render() {
    const [count, setCount] = useState(0); // 错误
    return <div>{count}</div>;
  }
}
```

## 2. Hook 使用的注意事项

### 2.1 使用状态时的异步更新

React 的 `useState` 和 `useReducer` 等 Hook 更新状态是异步的，因此在调用 `setState` 后，状态可能不会立即更新。这意味着你不能依赖状态立即更新的值进行后续计算。

```jsx
const [count, setCount] = useState(0);

// 错误：依赖于旧状态进行计算
setCount(count + 1);
console.log(count); // 可能不会立即反映最新的状态
```

为了正确更新状态，推荐使用函数式更新形式：

```jsx
setCount(prevCount => prevCount + 1);
```

### 2.2 依赖数组的使用

在 `useEffect`、`useCallback`、`useMemo` 等 Hook 中，依赖数组决定了副作用或计算何时执行。你需要正确设置依赖数组，以避免不必要的重新渲染或副作用的触发。

```jsx
useEffect(() => {
  // 仅当 count 或 name 改变时执行
  console.log(count, name);
}, [count, name]); // 依赖项应该正确列出
```

### 2.3 不要滥用 `useEffect`

`useEffect` 是用来处理副作用的，它会在组件渲染后执行。滥用 `useEffect` 可能会导致性能问题或副作用的重复执行。需要根据实际需要合理使用 `useEffect`，避免不必要的操作。

### 2.4 性能优化：`useMemo` 和 `useCallback`

如果你的组件依赖于复杂的计算或函数，在这些计算或函数不发生变化时，可以使用 `useMemo` 或 `useCallback` 来避免重复计算，提升性能。

```jsx
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
```

## 3. 总结

遵循 React Hook 的规则和注意事项对于确保应用的正确性和性能至关重要。记住：

* 只在函数组件或自定义 Hook 中使用 Hook；
* 在顶层调用 Hook，避免在循环或条件语句中调用；
* 理解并正确使用依赖数组，避免副作用的重复执行；
* 使用 `useMemo` 和 `useCallback` 进行性能优化。

通过遵循这些规则，你将能更有效地使用 React 的 Hook 功能，写出更清晰、更高效的代码。
