React.js 如何实现类似Angular的API分组管理最佳实践(Axios)
React + Axios 类Angular风格API目录规范实现
以下结构完全对齐Angular分层管理API的逻辑,和你之前使用的常量、服务分层写法一一对应,无额外学习成本。
目录结构
完全对齐Angular核心服务+特性模块服务的分层逻辑,所有API相关代码统一收敛管理:
src/ └── api/ # API统一管理根目录 ├── core/ # 全局请求核心配置(对应Angular全局HTTP拦截器、环境配置层) │ ├── constants.ts # 全局常量:接口根地址、通用状态码等 │ └── request.ts # Axios实例封装、全局请求/响应拦截器 ├── modules/ # 分业务模块的接口定义(对应Angular各特性模块的service目录) │ └── upload/ # 以上传模块为例,每个业务模块单独建文件夹 │ ├── constants.ts # 当前模块的接口路径常量 │ └── service.ts # 当前模块的接口请求方法封装 └── index.ts # 所有服务统一导出入口
各文件代码实现(和你Angular写法一一对应)
1. 全局核心配置层
api/core/constants.ts
全局通用常量,对应Angular环境配置文件中定义的API根地址:
// Vite项目用import.meta.env,CRA/webpack项目替换为process.env.REACT_APP_xxx即可 export const BASE_API_URL = import.meta.env.VITE_API_BASE_URL; export const SUCCESS_CODE = 200; export const AUTH_FAIL_CODE = 401;
api/core/request.ts
Axios实例与拦截器封装,对应Angular中配置了拦截器的HttpClient单例:
import axios from 'axios'; import { BASE_API_URL, AUTH_FAIL_CODE } from './constants'; const request = axios.create({ baseURL: BASE_API_URL, timeout: 10000, headers: { 'Content-Type': 'application/json' } }); // 请求拦截器:统一加token、请求标识,和Angular请求拦截器逻辑完全一致 request.interceptors.request.use((config) => { const token = localStorage.getItem('access_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 响应拦截器:统一处理错误、响应格式转换,和Angular响应拦截器逻辑完全一致 request.interceptors.response.use( (response) => response.data, (error) => { if (error.response?.status === AUTH_FAIL_CODE) { // 统一处理未登录逻辑:清缓存、跳登录页 localStorage.removeItem('access_token'); window.location.pathname = '/login'; } return Promise.reject(error); } ); export default request;
2. 业务模块层(以上传模块为例,完全匹配你写的Angular示例)
api/modules/upload/constants.ts
当前模块接口路径常量,和你Angular项目中写的constants.ts完全一致:
export const uploadData = `/uploadData`;
api/modules/upload/service.ts
当前模块请求方法封装,和你Angular项目中写的service.ts完全一致,类+单例的模式和Angular服务保持统一:
import request from '../../core/request'; import * as constants from './constants'; class UploadService { // 方法定义、参数和你Angular里的service方法完全对齐 uploadData(formData: FormData): Promise<any> { return request.post(constants.uploadData, formData, { headers: { 'Content-Type': 'multipart/form-data' } }); } } // 导出单例,和Angular服务的单例逻辑一致,无需重复实例化 export default new UploadService();
api/index.ts
服务统一导出入口,方便业务组件引入:
export { default as uploadService } from './modules/upload/service'; // 其他业务模块服务在此处追加导出即可,比如userService、orderService等
3. 组件中调用方式
和你Angular中引入服务调用的逻辑完全对齐,不需要在组件里写任何请求配置,直接调用服务方法即可:
import { uploadService } from '@/api'; import { useState } from 'react'; const UploadPage = () => { const [uploadRes, setUploadRes] = useState(null); const handleFileUpload = async (file: File) => { const formData = new FormData(); formData.append('file', file); // 对应你Angular里pipe(take(1)).subscribe的逻辑,await拿到的res就是subscribe中的返回值 try { const res = await uploadService.uploadData(formData); // 业务逻辑写在这里,和你之前// do something的位置完全对应 setUploadRes(res); } catch (err) { console.error('上传失败', err); } }; return ( <div> {/* 上传组件UI */} </div> ); }; export default UploadPage;
落地规范要点
- 所有接口路径必须定义在对应模块的
constants.ts中,禁止在service方法里硬编码接口地址 - 所有接口请求必须封装在对应模块的service类方法中,禁止在组件内直接写axios/fetch调用
- 业务模块按领域拆分,比如用户相关接口放
modules/user、订单相关接口放modules/order,和Angular特性模块的拆分逻辑一致 - 全局通用逻辑(token注入、错误处理、loading控制)全部收敛在
core/request.ts的拦截器中,业务模块不需要重复处理 - 所有service均导出单例,和Angular服务的单例模式保持一致,避免重复创建实例
内容的提问来源于stack exchange,提问作者Elliot
相关产品推荐
相关产品推荐

