自定义 Hook
定义
自定义Hook就是将常用的、跨组件的Hook功能或实现极致的逻辑与UI分离抽离成一个useXxx函数。
意义
- 自定义Hook实现了
逻辑与UI分离。 - 组件变得非常轻量,只负责使用数据并渲染UI,而所有复杂的状态管理、数据获取等
业务逻辑都委托给了自定义 Hook。 - 这让代码的可维护性和复用性得到了巨大的提升。
自定义 Hook 的诞生与解决方案
React Hook 的推出,特别是自定义 Hook,就是为了优雅地解决上述所有问题。
1. 逻辑复用:解决 “嵌套地狱” 和模式复杂性
自定义 Hook 允许你将组件逻辑提取到可重用的函数中。
它本身就是一个 JavaScript 函数,其名字以 “use” 开头,内部可以调用其他的 Hook。
- 之前 (使用 HOC):你需要用函数包裹你的组件,改变组件结构。
- 现在 (使用自定义 Hook):你直接在组件顶部调用一个函数(Hook)来引入所需的功能。组件树结构保持不变,非常干净。
举个例子
示例:一个获取用户数据的逻辑
// 1. 创建自定义 Hook:useUserData
import { useState, useEffect } from 'react';
function useUserData(userId) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetchUser(userId).then(data => {
setUser(data);
setLoading(false);
});
}, [userId]);
return { user, loading }; // 返回任何需要复用的值或函数
}
// 2. 在多个组件中复用这个逻辑
function UserProfile({ userId }) {
// 直接调用,像使用内置Hook一样
const { user, loading } = useUserData(userId);
if (loading) return <p>Loading...</p>;
return <h1>{user.name}</h1>;
}
function Avatar({ userId }) {
// 另一个组件复用同一套逻辑,但只关心user对象
const { user } = useUserData(userId);
return <img src={user.avatarUrl} alt={user.name} />;
}
没有额外的组件嵌套,逻辑清晰且直接。
2. 关注点分离:解决逻辑分散问题
使用自定义 Hook,你可以将一个大组件根据功能拆分成多个更小的、基于 Hook 的函数,而不是根据生命周期强行分割。
- 之前:一个 ComponentDidMount 里可能同时有数据获取、设置订阅、事件监听等所有初始化操作。
- 现在:你可以创建 useApiData, useSubscription, useEventListener 等多个自定义 Hook,然后在组件中并排调用它们。每个 Hook 都封装了一个完整的功能流。
function MyComplexComponent() {
// 数据获取逻辑
const data = useApiData('/api/data');
// 订阅逻辑
useSubscription('channel-name');
// 窗口大小监听逻辑
const windowSize = useWindowSize();
// 动画逻辑
useAnimation();
// ... 渲染逻辑
}
代码的可读性和可维护性大大提升。
为什么要自定义 Hook?
- 逻辑复用:避免在不同组件中复制粘贴相同的状态逻辑。
- 代码组织与可读性:将复杂组件的逻辑分解为更小的、功能单一的函数,使代码更清晰、更易于维护和测试。
- 简化组件树:避免了 HOC 和 Render Props 带来的
嵌套地狱,组件结构扁平化。 - 社区繁荣:可以轻松地使用社区共享的成千上万个自定义 Hook(如 react-use, ahooks 等库)来解决常见需求(网络请求、UI交互、动画等),极大提升开发效率。

浙公网安备 33010602011771号