自定义 Hook

定义

自定义Hook就是将常用的、跨组件的Hook功能或实现极致的逻辑与UI分离抽离成一个useXxx函数。

意义

  1. 自定义Hook实现了 逻辑与UI分离
  2. 组件变得非常轻量,只负责使用数据并渲染UI,而所有复杂的状态管理、数据获取等业务逻辑 都委托给了自定义 Hook。
  3. 这让代码的可维护性和复用性得到了巨大的提升。

自定义 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?

  1. 逻辑复用:避免在不同组件中复制粘贴相同的状态逻辑。
  2. 代码组织与可读性:将复杂组件的逻辑分解为更小的、功能单一的函数,使代码更清晰、更易于维护和测试。
  3. 简化组件树:避免了 HOC 和 Render Props 带来的嵌套地狱,组件结构扁平化。
  4. 社区繁荣:可以轻松地使用社区共享的成千上万个自定义 Hook(如 react-use, ahooks 等库)来解决常见需求(网络请求、UI交互、动画等),极大提升开发效率。
posted @ 2025-09-05 00:20  HuangBingQuan  阅读(18)  评论(0)    收藏  举报