自定义 Hooks 实战(下)

引言

在 React 开发中,自定义 Hooks 是提取组件逻辑、实现代码复用的强大工具。上篇文章我们介绍了自定义 Hooks 的基本概念,今天我们将深入三个实用的自定义 Hooks:useFetchuseDebounceuseInterval,看看它们如何解决实际开发中的常见问题。


1. useFetch - 优雅的数据获取

使用场景

处理 API 请求时,我们需要管理加载状态、错误处理和响应数据。useFetch 将这些逻辑封装成一个可复用的 Hook。

完整实现

typescript 复制代码
import { useState, useEffect } from 'react';

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err as Error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

使用示例

javascript 复制代码
function UserProfile({ userId }: { userId: string }) {
  const { data, loading, error } = useFetch<User>(
    `/api/users/${userId}`
  );

  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误:{error.message}</div>;
  if (!data) return null;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.email}</p>
    </div>
  );
}

2. useDebounce - 防抖优化

使用场景

在搜索框输入、窗口大小调整等高频触发场景中,useDebounce 可以延迟执行,避免不必要的计算和请求。

完整实现

typescript 复制代码
import { useState, useEffect } from 'react';

function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(timer);
    };
  }, [value, delay]);

  return debouncedValue;
}

使用示例

ini 复制代码
function SearchBox() {
  const [searchTerm, setSearchTerm] = useState('');
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  useEffect(() => {
    // 只在用户停止输入 500ms 后执行搜索
    if (debouncedSearchTerm) {
      fetchSearchResults(debouncedSearchTerm);
    }
  }, [debouncedSearchTerm]);

  return (
    <input
      type="text"
      value={searchTerm}
      onChange={(e) => setSearchTerm(e.target.value)}
      placeholder="搜索..."
    />
  );
}

3. useInterval - 定时器 Hook

使用场景

需要周期性执行某些操作(如轮询、动画、倒计时)时,useInterval 提供了声明式的定时器管理。

完整实现

javascript 复制代码
import { useEffect, useRef } from 'react';

function useInterval(callback: () => void, delay: number | null) {
  const savedCallback = useRef<() => void>();

  // 记住最新的回调函数
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // 设置定时器
  useEffect(() => {
    function tick() {
      savedCallback.current?.();
    }

    if (delay !== null) {
      const id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}

使用示例

scss 复制代码
function Counter() {
  const [count, setCount] = useState(0);

  useInterval(() => {
    setCount(count + 1);
  }, 1000);

  return <div>计数:{count}</div>;
}

总结对比

Hook 核心用途 关键特性 典型场景
useFetch 数据获取 自动管理 loading/error/state API 调用、数据加载
useDebounce 防抖优化 延迟值更新、自动清理定时器 搜索框、输入验证
useInterval 定时执行 支持动态延迟、自动清理 轮询、动画、倒计时

最佳实践建议

  1. 命名规范 :自定义 Hook 必须以 use 开头
  2. 依赖管理 :确保 useEffect 依赖数组完整
  3. 清理副作用:返回清理函数避免内存泄漏
  4. 类型安全:使用 TypeScript 泛型提高类型推断
  5. 测试覆盖:为自定义 Hook 编写单元测试
相关推荐
哈__2 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-push-notification-ios
react native·react.js·ios
GISer_Jing2 小时前
React全解析:从入门到精通实战指南
前端·react.js·前端框架
旭久3 小时前
react+echarts实现2d地图标记点与影响区域及可拖拽放大缩小等功能
react.js·echarts·swift
哈__3 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-haptic-feedback
javascript·react native·react.js
周淳APP3 小时前
【React Hook全家桶】大致过一遍React Hooks
前端·javascript·react.js·前端框架·react hooks
英俊潇洒美少年4 小时前
react 18 的fiber算法
前端·算法·react.js
吃西瓜的年年5 小时前
react(一)
前端·react.js·前端框架
每天都要进步哦5 小时前
React入门和快速上手
前端·vue.js·react.js·react
早點睡39013 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-swiper
javascript·react native·react.js