主题
结合 Pinia / Redux 管理请求状态
在前端项目中,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>
<script setup>
import { useUserStore } from "../stores/user";
const { list, loading, error, fetchUsers } = useUserStore();
</script>✅ 优势:
- 统一管理加载与错误状态
- 方便复用与缓存
- 更好地解耦组件与请求逻辑
二、在 React + Redux Toolkit 中使用 Axios
Redux Toolkit 提供了 createAsyncThunk 来封装异步请求逻辑,非常适合与 Axios 结合使用。
1. 安装依赖
bash
npm install @reduxjs/toolkit react-redux axios2. 创建 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(
<Provider store={store}>
<App />
</Provider>
);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 无缝结合,实现统一请求与状态管理。
- 对复杂项目,可结合缓存、重试与全局错误提示模块进一步优化。