什么是 React Hook?

React Hook 是 React 16.8 引入的特性,允许你在函数组件中使用状态(state)和其他 React 特性(如生命周期、副作用等),无需编写类组件。它的核心是逻辑复用代码简化

常见内置 Hooks:

  1. **useState**:管理组件状态。
    jsx

    复制

    1
    const [count, setCount] = useState(0);
  2. **useEffect**:处理副作用(如数据获取、DOM 操作)。
    jsx

    复制

    1
    2
    3
    useEffect(() => {
    document.title = `点击了 ${count} 次`;
    }, [count]); // 依赖项变化时触发
  3. **useContext**:访问 React 上下文。

  4. **useRef**:获取 DOM 引用或保存可变值。

  5. **useCallback/useMemo**:优化性能,缓存函数或值。


如何封装自定义 React Hook?

核心思想

将组件中的状态逻辑抽离为独立函数,通过组合内置 Hooks 实现复用。

封装步骤:

  1. 命名规范:函数名以 use 开头(如 useToggle)。
  2. 内部使用 Hooks:在自定义 Hook 中调用 useStateuseEffect 等。
  3. 返回必要数据:将状态或方法暴露给组件使用。

示例 1:封装 useToggle 控制开关状态

jsx

复制

1
2
3
4
5
6
7
8
9
10
11
12
13
import { useState } from 'react';

function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = () => setValue(!value);
return [value, toggle]; // 返回当前状态和切换函数
}

// 使用示例
function Component() {
const [isOn, toggleIsOn] = useToggle(false);
return <button onClick={toggleIsOn}>{isOn ? 'ON' : 'OFF'}</button>;
}

示例 2:封装 useFetch 处理数据请求

jsx

复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { useState, useEffect } from 'react';

function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
let isMounted = true; // 防止组件卸载后更新状态
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
if (isMounted) setData(result);
} catch (err) {
if (isMounted) setError(err);
} finally {
if (isMounted) setLoading(false);
}
};
fetchData();
return () => {
isMounted = false; // 清理时标记组件已卸载
};
}, [url]); // URL 变化时重新请求

return { data, loading, error };
}

// 使用示例
function UserList() {
const { data: users, loading, error } = useFetch('/api/users');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <ul>{users?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
}

封装注意事项:

  1. 隔离状态:每次调用 Hook 会独立维护其状态(多个组件使用同一 Hook 互不影响)。
  2. 依赖项处理:在 useEffect 中正确声明依赖数组,避免无限循环。
  3. 清理副作用:在 useEffect 返回清理函数(如移除事件监听、取消请求)。

总结

  • React Hook 是什么:函数组件中复用状态逻辑的工具。
  • 如何封装:提取通用逻辑到 useXxx 函数,组合内置 Hooks,返回所需状态或方法。
  • 优势:代码更简洁、逻辑更清晰、易于跨组件复用。