← 返回目录

第 18 卷

第 18 / 28 卷日期:

8// 正确:在函数组件中调用 Hooks 9function GoodComponent() {

10const [name, setName] = useName();

11return <input value={name} onChange={(e) => setName(e.target.value)} />;

12}

2. 实践层面的最佳规则(推荐遵守)

(1)自定义 Hooks 必须以 use 开头命名

规则:自定义 Hooks 的名称必须以「use」作为前缀(如 useRequest、useForm、useUser)。

原因:这是 React 官方的约定,目的是让开发者快速识别 Hooks,同时让 ESLint 等工具(如 eslintplugin-react-hooks)能够检测到 Hooks 的使用场景,避免违反核心规则(如在普通函数中调用)。

错误示例:const requestHook = () => { ... }(未以 use 开头,无法被识别为 Hooks);

正确示例:const useRequest = () => { ... }。

(2)依赖数组必须完整且准确

规则:对于 useEffect、useCallback、useMemo 等需要依赖数组的 Hooks,必须将回调函数中使用的所有组件内变量(state、props、函数等)都加入依赖数组。

原因:依赖数组的作用是告诉 React“当哪些变量变化时,需要重新执行回调函数/重新创建函数/重新计算结果”。若依赖数组不完整,会导致回调函数使用过期的变量(闭包陷阱),出现状态错乱、逻

辑异常等问题。

错误示例:

Code block

1 2function BadComponent({ id }) {

3const [data, setData] = useState(null);

4

5//错误:回调中使用了id,但未加入依赖数组,id变化时不会重新请求数据
6useEffect(() => {
7const fetchData = async () => {
8const res = await fetch(`https://api.example.com/data/${id}`);
9const data = await res.json();
10setData(data);
11};

正确示例:

Code block

1 2function GoodComponent({ id }) {

3const [data, setData] = useState(null);

4

5//正确:将id加入依赖数组,id变化时重新请求数据
6useEffect(() => {
7const fetchData = async () => {
8const res = await fetch(`https://api.example.com/data/${id}`);
9const data = await res.json();
10setData(data);
11};
12fetchData();
13}, [id]); //依赖数组包含所有用到的变量

14 15return <div>{data?.name}</div>;

16}

(3)避免在 Hooks 回调中执行副作用(useMemo/useCallback)

规则:useMemo 和 useCallback 的回调函数应是「纯函数」,无副作用(如 DOM 操作、网络请求、修改状态等);副作用应统一放在 useEffect 中处理。

原因:useMemo 和 useCallback 的核心作用是缓存,其回调函数的执行时机不确定(React 可能为了性能暂停/恢复执行),若包含副作用,可能导致副作用执行次数异常、逻辑错乱。

错误示例:

Code block

1 2function BadComponent() {

3const [count, setCount] = useState(0);

4

5//错误:useMemo回调中包含副作用(修改状态)
6useMemo(() => {
7setCount(count + 1); //副作用,执行时机不确定
8return count * 2;

正确示例:

Code block

1 2function GoodComponent() {

3const [count, setCount] = useState(0);
4const doubledCount = useMemo(() => {
5return count * 2; //纯函数,无副作用
6}, [count]);

7 8// 正确:副作用放在 useEffect 中

9useEffect(() => { 10setCount(prev => prev + 1);

11}, []);

12 13return <div>{doubledCount}</div>;

14}

(4)避免过度使用 Hooks

规则:不追求“ Hooks 数量最少”,但也避免不必要的 Hooks 拆分或滥用(如将简单状态拆分为多个 useState,或过度使用 useMemo/useCallback 缓存)。

原因:合理的 Hooks 拆分能提升代码可读性(如将不同功能的状态分开管理),但过度拆分会增加代码复杂度;过度使用缓存类 Hooks(useMemo/useCallback)会增加 React 的性能开销(缓存存

储、依赖对比),反而降低性能。

(5)清理 useEffect 中的副作用

规则:对于有“持续副作用”的 useEffect(如定时器、事件监听、网络请求),必须在回调函数中返回清理函数,用于组件卸载或依赖变化时清理副作用,避免内存泄漏。

示例:清理定时器

Code block

1 2function GoodComponent() {

3useEffect(() => { 4const timer = setInterval(() => {

5console.log('定时器执行');

6}, 1000);

全站分卷索引 · 28 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷
  11. 11第 11 卷
  12. 12第 12 卷
  13. 13第 13 卷
  14. 14第 14 卷
  15. 15第 15 卷
  16. 16第 16 卷
  17. 17第 17 卷
  18. 18第 18 卷
  19. 19第 19 卷
  20. 20第 20 卷
  21. 21第 21 卷
  22. 22第 22 卷
  23. 23第 23 卷
  24. 24第 24 卷
  25. 25第 25 卷
  26. 26第 26 卷
  27. 27第 27 卷
  28. 28第 28 卷