Pinia 状态管理
Pinia 是 Vue 3 的轻量级状态管理库,也是 Vue 官方推荐的状态管理方案。它比 Vuex 更简洁、更易用,同时提供了更好的 TypeScript 支持。
为什么选择 Pinia
本项目选择 Pinia 作为状态管理方案,主要基于以下优势:
- 简洁的 API:相比 Vuex,Pinia 的 API 更加简洁直观
- 完整的 TypeScript 支持:提供完整的类型推断,开发体验更佳
- 模块化设计:天然支持模块化,无需嵌套模块
- 轻量级:体积更小,性能更好
- Vue Devtools 支持:提供良好的开发调试体验
- 服务端渲染支持:支持 SSR 场景
项目集成
项目在 [src/store/index.ts] 中配置了 Pinia,并集成了 [pinia-plugin-persistedstate] 插件用于状态持久化:
ts
import type { App } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const store = createPinia();
store.use(piniaPluginPersistedstate);
export function setupStore(app: App<Element>) {
app.use(store);
}在 [src/main.ts] 中挂载状态管理:
ts
async function bootstrap() {
const app = createApp(App);
// 挂载状态管理
setupStore(app);
// ...
app.mount("#app", true);
}核心模块
项目中定义了多个状态管理模块,分别用于管理不同类型的数据:
用户模块 (user.ts)
管理用户相关的状态,包括用户信息和认证令牌:
ts
export const useUserStore = defineStore("app-user-store", {
state: () => ({
userInfo: {
userId: "",
username: "",
nickname: "",
avatar: "",
cover: "",
gender: 0,
phone: "",
},
token: "",
}),
getters: {
getUserInfo: state => state.userInfo,
getToken: state => state.token,
},
actions: {
setToken(token: string) {
this.token = token || "";
},
setUserInfo(info: UserInfo) {
this.userInfo = info;
},
async Login(params: LoginParams) {
// 登录逻辑
},
async GetUserInfo() {
// 获取用户信息
},
async Logout() {
// 登出逻辑
},
},
persist: {
key: "CURRENT-USER",
storage: window.localStorage,
// 生产环境使用加密存储
},
});主题模块 (theme.ts)
管理应用主题相关的状态:
ts
export const useThemeStore = defineStore("app-theme-store", {
state: () => ({
themeMode: "light", // 主题模式
themeColor: "#1976d2", // 主题色
themeColorList: [], // 主题色列表
isPageAnimate: true, // 是否开启动画
pageAnimateType: "fade-slide", // 动画类型
}),
getters: {
getThemeMode(): "light" | "dark" {
return this.themeMode;
},
getThemeColor(): string {
return this.themeColor;
},
// ...
},
actions: {
setThemeMode(mode: "light" | "dark"): void {
this.themeMode = mode;
},
setPageAnimateType(type: string): void {
this.pageAnimateType = type;
},
},
persist: {
key: "THEME-SETTING",
storage: window.localStorage,
},
});路由模块 (route.ts)
管理路由相关的状态,包括菜单和缓存组件:
ts
export const useRouteStore = defineStore("app-route-store", {
state: () => ({
menus: [], // 菜单列表
routers: [], // 路由列表
keepAliveComponents: [], // 需要缓存的组件
}),
getters: {
getMenus(): RouteRecordRaw[] {
return this.menus;
},
},
actions: {
setRouters(routers: RouteRecordRaw[]) {
this.routers = routers;
},
setMenus(menus: RouteRecordRaw[]) {
this.menus = menus;
},
setKeepAliveComponents(compNames: string[]) {
this.keepAliveComponents = compNames;
},
},
});应用模块 (app.ts)
管理全局应用状态:
ts
export const useAppStore = defineStore("app-global-store", {
state: () => ({
openEruda: false, // 是否开启 Eruda 调试工具
}),
getters: {
getOpenEruda(): boolean {
return this.openEruda;
},
},
actions: {
setOpenEruda(openEruda: boolean) {
this.openEruda = openEruda;
// 动态加载或移除 Eruda 脚本
},
},
});状态持久化
项目使用 [pinia-plugin-persistedstate] 插件实现状态持久化,可以将指定的状态存储到 localStorage 或 sessionStorage 中。
ts
persist: {
key: 'THEME-SETTING',
storage: window.localStorage,
serializer: {
serialize: isProdMode()
? (value: StateTree) => {
return encryptAES(value)
}
: JSON.stringify,
deserialize: isProdMode()
? (value: string) => {
return JSON.parse(decryptAES(value))
}
: JSON.parse
}
}在生产环境中,项目还对持久化数据进行了加密处理,提高数据安全性。
使用示例
在组件中使用 Pinia store:
vue
<script setup lang="ts">
import { useUserStore } from "@/store/modules/user";
import { useThemeStore } from "@/store/modules/theme";
// 获取 store 实例
const userStore = useUserStore();
const themeStore = useThemeStore();
// 访问状态
const userInfo = userStore.getUserInfo;
const themeMode = themeStore.getThemeMode;
// 调用 actions
userStore.setToken("new-token");
themeStore.setThemeMode("dark");
// 使用解构赋值访问状态
const { nickname, avatar } = userStore.getUserInfo;
</script>使用 computed 属性保持响应性:
ts
import { computed } from "vue";
import { useThemeStore } from "@/store/modules/theme";
const themeStore = useThemeStore();
// 保持响应性的 getter
const themeColor = computed(() => themeStore.getThemeColor);
// 双向绑定的 computed
const themeMode = computed({
get: () => themeStore.getThemeMode,
set: val => themeStore.setThemeMode(val),
});热更新支持
项目为所有 store 模块添加了热更新支持,提高开发体验:
ts
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot));
}最佳实践
- 模块化组织:按功能将状态划分为不同的模块
- 命名规范:store 名称使用
useXxxStore格式 - 状态持久化:合理使用持久化插件,敏感数据加密存储
- 类型安全:充分利用 TypeScript 类型推断
- 避免直接修改状态:通过 actions 修改状态,保持状态变更的可追踪性
Pinia 为项目提供了强大而灵活的状态管理能力,使得复杂应用的状态管理变得更加简单和可维护。