【无标题】

第一步:封装企业级 Axios (request.js)

企业级 Axios 通常需要处理:环境变量、请求拦截(加 Token)、响应拦截(统一错误处理)、超时设置以及取消请求的能力。

javascript 复制代码
// src/utils/request.js
import axios from 'axios';
import { message } from 'antd'; // 假设你用了 antd,或者用 alert

// 1. 创建实例
const service = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL || '/api', // 环境变量
  timeout: 10000, // 请求超时时间
});

// 2. 请求拦截器 (Request Interceptor)
service.interceptors.request.use(
  (config) => {
    // 在这里添加 Token 或其他公共参数
    const token = localStorage.getItem('token');
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 3. 响应拦截器 (Response Interceptor)
service.interceptors.response.use(
  (response) => {
    // 假设后端返回格式统一为 { code: 200, data: [], msg: '' }
    const res = response.data;
    
    if (res.code !== 200) {
      message.error(res.msg || '请求失败');
      
      // 特定错误处理,例如 401 跳转登录
      if (res.code === 401) {
        window.location.href = '/login';
      }
      return Promise.reject(new Error(res.msg));
    }
    return res; // 直接返回 data 部分,业务层拿到的就是纯净数据
  },
  (error) => {
    message.error(error.message || '网络异常');
    return Promise.reject(error);
  }
);

export default service;

第二步:封装通用的请求 Hook (useRequest.js)

这个 Hook 参考了你图片中的写法,但它做了增强:支持手动触发 (manual)、依赖刷新 (refreshDeps) 和参数透传。

javascript 复制代码
// src/hooks/useRequest.js
import { useState, useEffect, useCallback } from 'react';

/**
 * 通用的请求 Hook
 * @param {Function} api - 请求函数,必须返回一个 Promise
 * @param {Array} defaultParams - 默认参数
 * @param {Object} options - 配置项
 */
function useRequest(api, defaultParams = [], options = {}) {
  const { manual = false, refreshDeps = [] } = options;

  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(!manual);
  const [error, setError] = useState(null);

  // 请求函数
  const run = useCallback(
    async (...args) => {
      setLoading(true);
      setError(null);
      try {
        // 合并参数:默认参数 + 手动传入参数
        const finalParams = [...defaultParams, ...args];
        const res = await api(...finalParams);
        setData(res); // 注意:这里依赖 axios 拦截器返回了 res.data
        return res;
      } catch (err) {
        setError(err);
        throw err; // 抛出错误,让组件能捕获
      } finally {
        setLoading(false);
      }
    },
    [api, ...defaultParams] // 依赖项
  );

  // 自动执行逻辑
  useEffect(() => {
    if (!manual) {
      run();
    }
  }, [run, manual, ...refreshDeps]);

  return {
    data,
    loading,
    error,
    run,
  };
}

export default useRequest;

第三步:封装具体的业务 API 函数

这一步是为了把 axios 和具体的 URL 隔离,方便后期维护(比如后端改接口名,只改这里)。

javascript 复制代码
// src/api/user.js
import request from '@/utils/request';

// 导出请求函数,而不是直接调用
export const getUserList = (params) => {
  return request.get('/users', { params });
};

export const deleteUser = (id) => {
  return request.delete(`/users/${id}`);
};

第四步:组件调用模板(完全复刻你图片的风格)

现在,在组件中使用它就会非常清爽,完美匹配你的需求。

jsx 复制代码
// UserPage.jsx
import React from 'react';
import { getUserList } from '@/api/user';
import useRequest from '@/hooks/useRequest';

function UserPage() {
  // 🎯 重点:完全类似你图片中的调用方式
  // 第一个参数传 api 函数,第二个参数传默认参数,第三个参数传 options
  const { data, loading, error, run } = useRequest(getUserList, [], {
    // manual: true, // 如果需要手动触发,设为 true
  });

  // 手动触发示例(如果设置了 manual: true)
  const handleRefresh = () => {
    run(); 
  };

  if (loading) return <div>加载中...</div>;
  if (error) return <div>出错了: {error.message}</div>;

  return (
    <div>
      <h1>用户列表</h1>
      <button onClick={handleRefresh}>刷新数据</button>
      <ul>
        {data?.list?.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

export default UserPage;

总结:架构分层

  1. request.js:纯粹的 HTTP 工具,不管业务逻辑,只负责底层通信。
  2. api/*.js:接口契约,定义 URL 和参数结构。
  3. hooks/useRequest.js:逻辑复用层,处理 Loading、Error、重试等通用逻辑。
  4. Component :纯粹的 UI 层,只需要关心 dataloading,调用 run 即可。

这种结构非常稳定,在大型 React 项目中是标准的工程化实践。

相关推荐
Ian在掘金1 小时前
SSE 还是 WebSocket?从 AI 流式输出聊到实时通信选型
前端·人工智能
iiiiyu1 小时前
集合进阶(Map集合)
java·大数据·开发语言·数据结构·编程语言
雨雨雨雨雨别下啦1 小时前
心理健康AI助手 - 项目总结
前端·javascript·vue.js·人工智能·信息可视化
PILIPALAPENG1 小时前
第4周 Day 3:多 Agent 协作——让 Agent 们"组队干活"
前端·人工智能·python
小江的记录本1 小时前
【Java基础】核心关键字:final、static、volatile、synchronized、transient(附《思维导图》+《面试高频考点清单》)
java·前端·数据结构·后端·ai·面试·ai编程
风之舞_yjf1 小时前
Vue基础(32)_TodoList案例
前端·javascript·vue.js
青春喂了后端1 小时前
IntelliGit 前端订阅边界重构
前端·重构
月落归舟2 小时前
并发编程之volatile深度解析(二)
java·开发语言·volatile
lichenyang4532 小时前
HarmonyOS HMRouter 路由库 Demo 练习总结:从路由配置到商品管理增删改查
前端