ahooks useRequest 深度解析:一个 Hook 搞定所有请求

二、核心功能详解

1. 自动管理请求状态

javascript 复制代码
const { data, loading, error, run, refresh, cancel } = useRequest(
  fetchUserList,
  {
    manual: false,  // 自动执行
    defaultParams: [{ page: 1 }],  // 默认参数
  }
);

// run: 手动触发
// refresh: 使用上次参数重新请求
// cancel: 取消当前请求

2. 防抖与节流

javascript 复制代码
// 搜索场景:防抖
const { data, loading } = useRequest(searchAPI, {
  debounceWait: 300,  // 300ms 防抖
  manual: true,
});

// 滚动加载:节流
const { run } = useRequest(loadMore, {
  throttleWait: 1000,  // 1s 节流
  manual: true,
});

3. 轮询

javascript 复制代码
// 每 3 秒轮询一次
const { data } = useRequest(getStatus, {
  pollingInterval: 3000,
  pollingWhenHidden: false,  // 页面隐藏时停止轮询
});

// 条件轮询
const { data } = useRequest(getJobStatus, {
  pollingInterval: 2000,
  pollingErrorRetryCount: 3,  // 错误重试次数
  onSuccess: (result) => {
    if (result.status === 'completed') {
      // 完成后停止轮询
      return false;
    }
  }
});

4. 依赖刷新

javascript 复制代码
const [userId, setUserId] = useState('1');

const { data } = useRequest(
  () => fetchUser(userId),
  {
    refreshDeps: [userId],  // userId 变化时自动重新请求
  }
);

5. 缓存机制

javascript 复制代码
// SWR 模式:先返回缓存,后台更新
const { data, loading } = useRequest(fetchUser, {
  cacheKey: 'user-data',
  staleTime: 5000,  // 5s 内认为数据新鲜
  cacheTime: 300000,  // 缓存保留 5 分钟
});

// 清除缓存
import { clearCache } from 'ahooks';
clearCache('user-data');

6. 错误重试

javascript 复制代码
const { data, error, retry } = useRequest(unstableAPI, {
  retryCount: 3,  // 失败后重试 3 次
  retryInterval: 1000,  // 重试间隔 1s
  onError: (error, params) => {
    console.log('请求失败', error);
  }
});

三、进阶场景

并行请求

javascript 复制代码
const user = useRequest(fetchUser);
const posts = useRequest(fetchPosts);
const comments = useRequest(fetchComments);

const loading = user.loading || posts.loading || comments.loading;

串行请求

javascript 复制代码
const { data: user } = useRequest(fetchUser);

const { data: posts } = useRequest(
  () => fetchUserPosts(user.id),
  {
    ready: !!user,  // user 存在时才执行
    refreshDeps: [user],
  }
);

分页加载

javascript 复制代码
function UserList() {
  const { data, loading, loadMore, loadingMore, noMore } = useRequest(
    (d) => fetchList({ page: d?.nextPage || 1 }),
    {
      loadMore: true,
      isNoMore: (d) => !d?.hasMore,
    }
  );
  
  return (
    <>
      {data?.list.map(item => <Item key={item.id} {...item} />)}
      {!noMore && (
        <Button onClick={loadMore} loading={loadingMore}>
          加载更多
        </Button>
      )}
    </>
  );
}

乐观更新

javascript 复制代码
const { run: deleteItem } = useRequest(deleteAPI, {
  manual: true,
  onBefore: (params) => {
    // 立即更新 UI
    setList(list => list.filter(item => item.id !== params[0]));
  },
  onError: (error, params) => {
    // 失败时回滚
    message.error('删除失败');
    refresh();
  }
});

四、与其他方案对比

特性 useRequest React Query SWR
学习成本 低 中 低
功能完整度 高 很高 中
包体积 小 较大 小
防抖节流 内置 需自己实现 需自己实现
轮询 内置 内置 需配置
TypeScript 良好 优秀 良好

五、最佳实践

  1. 合理使用缓存:列表、详情等读多写少的数据适合缓存
  2. 设置合适的防抖时间:搜索建议 300-500ms
  3. 避免过度轮询:根据业务需求设置合理的轮询间隔
  4. 善用 ready 参数:避免无效请求
  5. 统一错误处理:在全局配置中处理通用错误
javascript 复制代码
// 全局配置
import { configResponsive } from 'ahooks';

configResponsive({
  onError: (error) => {
    if (error.code === 401) {
      // 统一处理未登录
      redirectToLogin();
    }
  }
});

六、源码解析(简化版)

useRequest 的核心实现思路:

javascript 复制代码
function useRequest(service, options) {
  const [state, setState] = useState({
    data: undefined,
    loading: false,
    error: undefined,
  });
  
  const run = useCallback(async (...params) => {
    setState(s => ({ ...s, loading: true }));
    
    try {
      const data = await service(...params);
      setState({ data, loading: false, error: undefined });
    } catch (error) {
      setState(s => ({ ...s, loading: false, error }));
    }
  }, [service]);
  
  useEffect(() => {
    if (!options.manual) {
      run(...(options.defaultParams || []));
    }
  }, []);
  
  return { ...state, run };
}

实际实现还包括:

  • 防抖节流的 debounce/throttle 包装
  • 轮询的 setInterval 管理
  • 缓存的 Map 存储
  • 依赖追踪的 useEffect
  • 请求取消的 AbortController

总结

useRequest 是一个功能强大且易用的请求管理 Hook,它封装了日常开发中 90% 的请求场景。通过合理使用其提供的能力,可以大幅减少样板代码,提升开发效率。

推荐在中小型项目中直接使用 useRequest,大型项目可以考虑 React Query 获得更强的数据管理能力。

如果这篇文章对你有帮助,欢迎点赞收藏!

相关推荐
2501_944521594 小时前
Ramda 跨端三方库仓颉适配全流程
开发语言·javascript·flutter·php
Ken_11155 小时前
小体积附件下载正常,大附件下载异常
javascript
wangchunyu1146 小时前
JAVA CompletableFuture异步编程实战
java·开发语言·python
变与不变8066 小时前
jQuery怎么使用
前端·javascript
paopaokaka_luck6 小时前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
Thomas.Sir6 小时前
第9课:SpringBoot4.x Web开发基础:WebMvc自动配置、静态资源、请求参数接收
java·spring boot
仰望.6 小时前
vue 表格组件 vxe-table 树表格懒加载支持拖拽排序的详细用法
前端·javascript·vue.js·vxe-table
程序 代码狂人7 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
2501_944521597 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
程序员初一8 小时前
我把跑了两年 WordPress 的机器重装了一遍,顺便把面板卸了
javascript