Pinia 状态管理:模块化、持久化与“权限联动”落地

Pinia 状态管理:模块化、持久化与"权限联动"落地

很多项目上 Pinia 不难用,但容易用成两种极端:

  • 全部状态都塞进 store,组件越来越"胖"
  • store 只存 token,其它状态各自维护,协作成本变高

这篇按"项目落地"的方式讲 Pinia:

  • store 如何分模块(领域边界)
  • state/ getter / action 如何设计(可维护)
  • 持久化存什么、不存什么(安全与一致性)
  • 与 Axios 拦截器、权限路由怎么联动成闭环

目标是:写出来的 store 不仅能跑,还能在项目迭代中长期稳定。


1. Pinia 在项目里解决什么问题

  • 跨页面共享状态:登录态、用户信息、字典、主题配置
  • 减少 props/emit 链路:避免层层传递
  • 统一副作用入口:把"请求 + 缓存 + 失效"放在 store action

2. store 怎么分模块(建议的边界)

按"领域"拆,而不是按"页面"拆:

  • useUserStore:token、用户信息、角色/权限、登出
  • useAppStore:主题/布局、侧边栏折叠、全局 loading
  • useDictStore:字典缓存(下拉框、枚举)

避免:

  • 为每个页面新建一个 store(复用差、维护重)

3. 选项式 vs 组合式:先统一团队写法

Pinia 支持两种写法:

  • 选项式(Options Store):更像 Vuex,结构清晰
  • 组合式(Setup Store):更贴近 Composition API,可自由组合逻辑

建议:团队里统一一种写法,避免同一项目两套风格混用。


4. 一个实用的 user store 形态(建议做成"登录态权威源")

ts 复制代码
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: '',
    userInfo: null as null | { id: number; name: string; role: string },
  }),
  getters: {
    isLogin: (s) => !!s.token,
    role: (s) => s.userInfo?.role,
  },
  actions: {
    setToken(token: string) {
      this.token = token
    },
    setUserInfo(info: any) {
      this.userInfo = info
    },
    async logout() {
      this.token = ''
      this.userInfo = null
    },
  },
})

建议:

  • 让"读状态"都从 getters 出口走(组件依赖更清晰)
  • action 负责副作用(请求、缓存、失效)

5. 持久化:token/用户信息怎么存更稳

常见做法:

  • 仅持久化 token
  • userInfo 在刷新后重新拉取(更可信、更安全)

如果你希望持久化(例如减少首屏请求),至少做到:

  • token 过期后要能自动清理
  • 角色变化后要能"强制刷新权限"

(持久化插件的接入方式很多,这里核心是原则,不强调具体库。)

工程建议(更稳):

  • 只持久化 token
  • userInfo 在刷新后重新拉取(避免角色变化、权限变更导致前端缓存"过期")
  • 登出时清理 token 并重置所有权限相关 store

6. Pinia 和 Axios 拦截器联动

典型目标:

  • 请求头自动携带 token
  • 401 统一踢下线/跳登录

伪代码示意:

js 复制代码
axios.interceptors.request.use((config) => {
  const userStore = useUserStore()
  if (userStore.token) config.headers.Authorization = userStore.token
  return config
})

axios.interceptors.response.use(
  (res) => res,
  (err) => {
    if (err.response?.status === 401) {
      const userStore = useUserStore()
      userStore.logout()
      router.replace('/login')
    }
    return Promise.reject(err)
  }
)

关键点:

  • 让"登录态失效"的处理在一个地方收敛
  • store 只做状态与动作,路由跳转由响应拦截器或路由守卫兜底

7. Pinia 和权限路由联动(动态菜单/路由)

常见需求:

  • 不同角色展示不同菜单
  • 路由守卫按角色放行/拒绝

落地方式:

  • userStore.userInfo.role 作为权限源
  • permissionStore.routes 作为可访问路由表
  • 登录后拉取用户信息 -> 生成动态路由 -> router.addRoute

建议:

  • 动态路由生成要可重入(刷新、重新登录都能跑一遍)
  • 退出登录要清理动态路由与缓存菜单

工程落地的关键点:

  • userStore 只负责"登录态、用户信息、权限源数据"
  • permissionStore 负责"根据权限源生成可访问路由/菜单"
  • 路由守卫负责"什么时候生成、什么时候注入、什么时候重建"

8. 常见坑(反模式清单)

  • 组件外直接解构 store:会丢响应
  • 把接口响应原样塞进 store:字段不稳定,后续很难维护
  • 登录态与权限不同步:只持久化 token,没刷新 userInfo 导致"菜单错乱"

再补两个非常常见的坑:

  • store 里放 UI 临时状态(例如某个弹窗开关):会导致 store 膨胀、依赖混乱
  • action 里直接 return 后端原始结构:页面不得不写兼容逻辑,违背"契约"

9. 总结

  • Pinia 的价值在"状态与副作用统一收敛"
  • store 以领域拆分,不要按页面拆
  • token 持久化,用户信息建议刷新后重新拉取
  • 结合 Axios 拦截器与路由守卫,实现登录态与权限的闭环
相关推荐
清心歌8 分钟前
CopyOnWriteArrayList 实现原理
java·开发语言
jiayong2316 分钟前
第 8 课:开始引入组合式函数
前端·javascript·学习
田八20 分钟前
聊聊AI的发展史,AI的爆发并不是偶然
前端·人工智能·程序员
Java成神之路-29 分钟前
通俗易懂理解 Spring MVC 拦截器:概念、流程与简单实现(Spring系列16)
java·spring·mvc
zhanghongbin0130 分钟前
AI 采集器:Claude Code、OpenAI、LiteLLM 监控
java·前端·人工智能
计算机毕设vx_bysj686932 分钟前
【免费领源码】77196基于java的手机银行app管理系统的设计与实现 计算机毕业设计项目推荐上万套实战教程JAVA,node.js,C++、python、大屏数据可视化
java·mysql·智能手机·课程设计
忘梓.33 分钟前
墨色规则与血色节点:C++红黑树设计与实现探秘
java·开发语言·c++
hhh3u3u3u33 分钟前
Visual C++ 6.0中文版安装包下载教程及win11安装教程
java·c语言·开发语言·c++·python·c#·vc-1
IT_陈寒35 分钟前
Python的列表推导式里藏了个坑,差点让我加班到凌晨
前端·人工智能·后端
星河耀银海36 分钟前
C++ 模板进阶:特化、萃取与可变参数模板
java·开发语言·c++