# 结合 Pinia / Redux 管理请求状态

URL: https://caijiao.org/axios/in-framework/state
Source: docs/axios/in-framework/state.md
Description: 学习如何在 Vue3 的 Pinia 与 React 的 Redux 中结合 Axios 管理请求状态，实现加载中、成功、失败状态的统一控制与缓存机制。

在前端项目中，Axios 通常与状态管理库（如 **Pinia**、**Redux**）配合使用，以实现全局统一的请求状态（loading、error、data）管理。  
这可以让组件逻辑更清晰，避免重复的请求控制代码。

## 一、在 Vue3 + Pinia 中使用 Axios

Pinia 是 Vue3 官方推荐的状态管理库，搭配 Axios 可以轻松管理异步数据请求。

### 1. 安装依赖

```bash
npm install pinia axios
````

在入口文件中注册 Pinia：

```js
// main.js
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";

const app = createApp(App);
app.use(createPinia());
app.mount("#app");
```

### 2. 创建 Axios 实例

```js
// src/utils/request.js
import axios from "axios";

const request = axios.create({
  baseURL: "/api",
  timeout: 8000,
});

request.interceptors.response.use(
  (res) => res.data,
  (err) => Promise.reject(err)
);

export default request;
```

### 3. 定义 Pinia Store

```js
// src/stores/user.js
import { defineStore } from "pinia";
import request from "../utils/request";

export const useUserStore = defineStore("user", {
  state: () => ({
    list: [],
    loading: false,
    error: null,
  }),
  actions: {
    async fetchUsers() {
      this.loading = true;
      this.error = null;
      try {
        const res = await request.get("/users");
        this.list = res;
      } catch (err) {
        this.error = err.message || "请求失败";
      } finally {
        this.loading = false;
      }
    },
  },
});
```

### 4. 在组件中使用

```vue
<template>
  <div>
    <button @click="fetchUsers">加载用户</button>
    <p v-if="loading">加载中...</p>
    <p v-if="error" class="error">{{ error }}</p>
    <ul>
      <li v-for="u in list" :key="u.id">{{ u.name }}</li>
    </ul>
  </div>
</template>


```

> ✅ **优势**：
>
> * 统一管理加载与错误状态
> * 方便复用与缓存
> * 更好地解耦组件与请求逻辑

## 二、在 React + Redux Toolkit 中使用 Axios

Redux Toolkit 提供了 `createAsyncThunk` 来封装异步请求逻辑，非常适合与 Axios 结合使用。

### 1. 安装依赖

```bash
npm install @reduxjs/toolkit react-redux axios
```

### 2. 创建 Axios 实例

```js
// src/api/request.js
import axios from "axios";

const request = axios.create({
  baseURL: "/api",
  timeout: 8000,
});

request.interceptors.response.use(
  (res) => res.data,
  (err) => Promise.reject(err)
);

export default request;
```

### 3. 定义 Slice 与异步请求

```js
// src/store/userSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import request from "../api/request";

export const fetchUsers = createAsyncThunk("users/fetch", async () => {
  return await request.get("/users");
});

const userSlice = createSlice({
  name: "user",
  initialState: { list: [], loading: false, error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.loading = false;
        state.list = action.payload;
      })
      .addCase(fetchUsers.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

export default userSlice.reducer;
```

### 4. 配置 Store

```js
// src/store/index.js
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./userSlice";

const store = configureStore({
  reducer: {
    user: userReducer,
  },
});

export default store;
```

在入口文件中注入：

```js
// main.jsx
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  
);
```

### 5. 在组件中使用

```jsx
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchUsers } from "../store/userSlice";

function UserList() {
  const dispatch = useDispatch();
  const { list, loading, error } = useSelector((state) => state.user);

  useEffect(() => {
    dispatch(fetchUsers());
  }, [dispatch]);

  if (loading) return <p>加载中...</p>;
  if (error) return <p>错误：{error}</p>;

  return (
    <ul>
      {list.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}

export default UserList;
```

## 三、Pinia vs Redux 对比

| 特性     | Pinia（Vue）     | Redux Toolkit（React）    |
| ------ | -------------- | ----------------------- |
| 语法风格   | 简洁、声明式         | 结构化、约束性强                |
| 异步请求支持 | 直接写在 actions 中 | `createAsyncThunk` 内置支持 |
| 状态管理方式 | 响应式（Reactive）  | 不可变（Immutable）          |
| 学习曲线   | 低              | 中等                      |
| 类型支持   | 优秀（TS 友好）      | 优秀（TS 原生）               |

## 四、总结

* **Pinia** 适合 Vue3，逻辑直观，轻量易上手。
* **Redux Toolkit** 简化了 Redux 使用，推荐用于中大型 React 项目。
* 两者都可以与 Axios 无缝结合，实现统一请求与状态管理。
* 对复杂项目，可结合缓存、重试与全局错误提示模块进一步优化。
