11、统一状态管理架构:Vuex、Pinia、Redux 的融合策略

141 阅读3分钟

🪜 写在前面

状态管理是前端架构中最容易“滥用”,却最影响维护性与性能的模块。

在实际开发中,你是否遇到这些问题:

  • 页面状态和全局状态混乱在一起
  • store 巨大无比,一个值改动引发全局重渲
  • 表单页退出再进来,数据全部丢失
  • 组件之间 props 和 emit 层层传递,毫无乐趣

本篇我们将:

  • 拆解状态管理的分层思维
  • 统一 Vue/Pinia/Vuex/Redux 的状态分布结构
  • 给出状态归属、持久化、模块复用的实践方案
  • 给出不同项目适用的架构模型

📦 一、状态管理的分类与归属建议

我们将状态拆成 4 层:

层级状态类型举例建议位置
① 页面状态表单输入、分页、loadingformData、currentPage组件内部 / setup()
② 业务状态当前用户信息、购物车内容userInfo、cartList模块 store(Pinia)
③ 全局状态多模块共享、应用级别主题、token、权限全局 store
④ 派发逻辑状态之间的数据流A 模块更新后通知 BEventBus / 中间 store / 联动处理

✅ 二、推荐架构结构(以 Vue3 + Pinia 为例)

src/
├── modules/
│   └── user/
│       ├── views/...
│       ├── store.ts         # 用户业务状态
│       ├── api.ts
├── store/                   # 全局状态
│   ├── app.ts               # 主题、语言
│   ├── auth.ts              # 登录 token、权限列表
│   └── index.ts

示例:业务模块 store(Pinia)

// modules/user/store.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    info: null,
  }),
  actions: {
    async fetch() {
      this.info = await getUserInfo()
    },
  },
})

🧠 三、不同状态场景的最佳放置方案

🎯 场景1:表单输入数据(页面私有)

const formData = reactive({ name: '', age: '' })
// ✅ 不应放入 store

🎯 场景2:用户登录态(全局共享)

const authStore = useAuthStore()
const token = authStore.token

🎯 场景3:商品选择列表(多页面共享)

// 使用模块级 store:useGoodsStore()

🎯 场景4:页面跳转后状态还原

✅ 方法1:store 缓存 + 页面 onMounted 时恢复 ✅ 方法2:使用 useRouteQuery(),在 query 中保持关键状态 ✅ 方法3:sessionStorage 临时保存页面缓存数据


🔁 四、状态更新联动与事件分发策略

当模块 A 修改状态后,希望模块 B 响应更新,可以用:

✅ 方法1:订阅监听(Pinia)

// 在模块 B 中监听
userStore.$subscribe((mutation, state) => {
  if (mutation.storeId === 'user' && mutation.events.key === 'info') {
    console.log('用户信息变化了')
  }
})

✅ 方法2:中间状态派发器(推荐)

创建一个通用的 eventStore

export const useEventStore = defineStore('event', {
  state: () => ({ events: {} }),
  actions: {
    fire(event, payload) {
      this.events[event] = payload
    },
    clear(event) {
      delete this.events[event]
    },
  },
})

模块 A:

eventStore.fire('refresh-table', { force: true })

模块 B:

watch(() => eventStore.events['refresh-table'], (val) => {
  if (val?.force) refreshTable()
})

🧲 五、状态持久化方案(持久登录 / 记住用户)

使用 pinia-plugin-persistedstate 插件:

npm i pinia-plugin-persistedstate

在入口注册:

import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPersist)

定义持久化字段:

export const useAuthStore = defineStore('auth', {
  state: () => ({ token: '' }),
  persist: true,
})

📊 六、Redux/Vuex/Pinia 对比与融合建议

特性VuexPinia ✅Redux
写法简洁✅(Toolkit)
类型支持一般
分模块能力
DevTools 支持
学习成本
推荐场景Vue2 老项目Vue3 全系React 中大型系统

🧩 七、统一状态管理实践建议

  1. 所有页面状态优先使用 setup 内部 ref/ reactive 管理
  2. 所有共享业务状态都用模块化 store
  3. 所有跨模块状态联动使用 eventStore / subscribe
  4. 不建议把“短生命周期状态”放入 store,例如临时分页配置、tabIndex
  5. store 命名统一采用功能命(useUserStoreuseAuthStore

✅ 八、封装建议(高级实践)

  • useRouteQueryState():自动将分页等状态绑定到 URL
  • usePersistedRef():封装 localStorage/SessionStorage 自动存取
  • createScopedStore():为多 tab 设计私有状态
  • pinia-auto-module:支持自动生成模块 + 动态加载 store

🧠 总结一句话

前端状态不是“能用就放 store”,而是“局部用局部管,模块用模块管,全局才上全局 store”。


接下来进入「表单系统架构与平台化设计」相关内容:

👉 《表单系统设计:动态表单 + 校验 + 可配置化》