# 在 React 中集成 Axios

URL: https://caijiao.org/axios/in-framework/react
Source: docs/axios/in-framework/react.md
Description: 学习如何在 React 项目中集成 Axios，包括封装请求模块、使用 useEffect 发起请求、处理状态和错误，以及结合 Context 或 Redux 管理全局请求。

Axios 在 React 项目中非常常见，用于与后端 API 通信。通过合理封装，可以让代码结构更清晰、可维护性更高。

## 一、安装 Axios

在 React 项目中安装 Axios：

```bash
npm install axios
# 或
yarn add axios
````

## 二、基础用法示例

在组件中直接发起请求：

```jsx
import React, { useEffect, useState } from "react";
import axios from "axios";

export default function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    axios.get("/api/users").then((res) => {
      setUsers(res.data);
    });
  }, []);

  return (
    <ul>
      {users.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}
```

> 📘 建议使用 `useEffect` 控制请求生命周期，防止组件卸载时内存泄漏。

## 三、封装 Axios 实例

在大型项目中，推荐创建独立的 `request.js`：

```js
// src/utils/request.js
import axios from "axios";

const request = axios.create({
  baseURL: import.meta.env.VITE_API_URL || "/api",
  timeout: 8000,
});

request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem("token");
    if (token) config.headers.Authorization = `Bearer ${token}`;
    return config;
  },
  (error) => Promise.reject(error)
);

request.interceptors.response.use(
  (res) => res.data,
  (error) => {
    console.error("API Error:", error);
    return Promise.reject(error);
  }
);

export default request;
```

在组件中使用：

```jsx
import React, { useEffect, useState } from "react";
import request from "../utils/request";

function Posts() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    request.get("/posts").then(setPosts);
  }, []);

  return (
    <div>
      <h3>文章列表</h3>
      {posts.map((p) => (
        <p key={p.id}>{p.title}</p>
      ))}
    </div>
  );
}

export default Posts;
```

## 四、使用自定义 Hook 封装请求逻辑

可以封装一个通用的 `useRequest` Hook：

```js
import { useEffect, useState } from "react";
import request from "../utils/request";

export function useRequest(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    setLoading(true);
    request(url, options)
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false));
  }, [url]);

  return { data, loading, error };
}
```

使用示例：

```jsx
import { useRequest } from "../hooks/useRequest";

function Dashboard() {
  const { data, loading, error } = useRequest("/api/stats");

  if (loading) return <p>加载中...</p>;
  if (error) return <p>加载失败：{error.message}</p>;

  return <div>用户总数：{data.totalUsers}</div>;
}
```

## 五、与 Redux / Context 集成

在全局状态管理中，可以将 Axios 实例注入到中间件中（如 Redux Toolkit 的 thunk），统一处理请求。

```js
// example using Redux Toolkit
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import request from "../utils/request";

export const fetchUsers = createAsyncThunk("users/fetch", async () => {
  return await request.get("/users");
});

const usersSlice = createSlice({
  name: "users",
  initialState: { list: [], status: "idle" },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.status = "loading";
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.list = action.payload;
        state.status = "succeeded";
      });
  },
});

export default usersSlice.reducer;
```

## 六、错误提示与全局拦截

在拦截器中统一弹出错误提示（结合 Toast / Modal）：

```js
import { message } from "antd"; // 或其他 UI 库

request.interceptors.response.use(
  (res) => res,
  (error) => {
    message.error(error.response?.data?.message || "请求失败");
    return Promise.reject(error);
  }
);
```

## 七、总结

* React 中推荐封装 Axios 实例，结合 Hook 管理请求状态。
* 使用拦截器统一处理 Token 和错误。
* 在 Redux / Context 层集成 Axios，有助于全局状态与请求同步。
* 对于高并发场景，可结合 `axios.all`、`AbortController` 等优化性能。
