Vue3/Pinia(TypeScript):如何为独立Action处理数据、错误与加载状态
Pinia+TypeScript实现Action独立状态管理(Vue3)
问题核心
需要为每个Store Action单独维护loading、error状态,避免全局状态冲突,同时严格遵守TypeScript的类型约束(不能随意修改User接口结构)。
解决方案1:为单个Action单独声明状态
直接在Store的state中为getMe Action专属添加加载和错误状态,结构清晰,适合少量Action的场景。
修改Auth Store代码
import { defineStore } from "pinia"; import AuthService from "@/api/modules/auth"; interface User { email: string; first_name: string; last_name: string; force_password_change: boolean; groups: string[]; has_2fa_enabled: boolean; is_staff: boolean; lang: string; last_password_change: string; permissions: string[]; session_expiry_date: string; uid: string; } export const useAuthStore = defineStore({ id: "auth", state: () => ({ user: {} as User, // 为getMe单独设置状态,避免与其他Action冲突 getMeLoading: false, getMeError: null as Error | null, }), actions: { async getMe() { // 初始化状态 this.getMeLoading = true; this.getMeError = null; try { const userData = await AuthService.getMe(); this.user = userData; return userData; } catch (error) { // 捕获并存储错误 this.getMeError = error as Error; throw error; // 可选:让组件也能捕获错误做后续处理 } finally { // 请求结束后无论成功失败都关闭加载状态 this.getMeLoading = false; } }, }, });
组件中使用(App.vue)
<script setup lang="ts"> import { useAuthStore } from "@/stores"; import { storeToRefs } from "pinia"; const userStore = useAuthStore(); // 直接解构获取Action专属状态 const { user, getMeLoading, getMeError } = storeToRefs(userStore); // 发起请求并处理状态 const fetchUser = async () => { try { await userStore.getMe(); console.log("用户数据:", user.value); } catch (err) { console.error("获取用户失败:", getMeError.value); } }; fetchUser(); </script>
解决方案2:统一管理多Action状态(扩展性更强)
如果Store中有多个Action需要独立状态,用一个对象统一管理,更易维护和扩展。
修改Auth Store代码
import { defineStore } from "pinia"; import AuthService from "@/api/modules/auth"; interface User { email: string; first_name: string; last_name: string; force_password_change: boolean; groups: string[]; has_2fa_enabled: boolean; is_staff: boolean; lang: string; last_password_change: string; permissions: string[]; session_expiry_date: string; uid: string; } // 定义Action状态的通用接口 interface ActionState { loading: boolean; error: Error | null; } export const useAuthStore = defineStore({ id: "auth", state: () => ({ user: {} as User, // 用对象统一管理所有Action的状态 actionStates: { getMe: { loading: false, error: null } as ActionState, // 可添加其他Action的状态,比如login/logout等 } as Record<string, ActionState>, }), getters: { // 封装getters方便组件直接获取 getMeLoading: (state) => state.actionStates.getMe.loading, getMeError: (state) => state.actionStates.getMe.error, }, actions: { async getMe() { const stateKey = "getMe"; this.actionStates[stateKey].loading = true; this.actionStates[stateKey].error = null; try { const userData = await AuthService.getMe(); this.user = userData; return userData; } catch (error) { this.actionStates[stateKey].error = error as Error; throw error; } finally { this.actionStates[stateKey].loading = false; } }, // 其他Action示例:login async login(credentials: { email: string; password: string }) { const stateKey = "login"; if (!this.actionStates[stateKey]) { // 初始化未定义的Action状态 this.actionStates[stateKey] = { loading: false, error: null }; } this.actionStates[stateKey].loading = true; this.actionStates[stateKey].error = null; try { // 登录逻辑 // const result = await AuthService.login(credentials); // ... } catch (error) { this.actionStates[stateKey].error = error as Error; throw error; } finally { this.actionStates[stateKey].loading = false; } }, }, });
组件中使用
<script setup lang="ts"> import { useAuthStore } from "@/stores"; import { storeToRefs } from "pinia"; const userStore = useAuthStore(); // 通过getters直接获取状态 const { user, getMeLoading, getMeError } = storeToRefs(userStore); const fetchUser = async () => { try { await userStore.getMe(); console.log("用户数据:", user.value); } catch (err) { console.error("获取用户失败:", getMeError.value); } }; fetchUser(); </script>
额外优化:完善Service的类型约束
避免any类型,明确返回值类型让TypeScript更好地发挥作用:
import { Api } from "../apiSettings"; class AuthService { // 明确返回Promise<User>,而非any async getMe(): Promise<User> { const response = await Api.get("api/auth/me/"); // 根据实际API响应结构调整,假设返回数据在response.data中 return response.data as User; } } export default new AuthService();
内容的提问来源于stack exchange,提问作者Jer
相关产品推荐
相关产品推荐

