Skip to content

Vuex 与 Pinia

作者:青见春山
发表于:2026-07-29
字数统计:4500 字
预计阅读16分钟

涵盖 Vuex 与 Pinia 在 5 维度上的差异、Pinia 移除 mutations 的原因、模块化对比、Vue 3 项目选型与迁移方案。

一、标准面试回答(1 分钟)

Vuex 和 Pinia 都是 Vue 的状态管理库,Pinia 是 Vue 3 官方推荐的新方案,可以看作是 Vuex 5 的雏形,在设计上更简洁、类型推断更好、API 更现代化

从五个维度对比:

第一,设计理念

Vuex 采用单一状态树,通过 mutations(同步修改)和 actions(异步操作)区分修改方式;Pinia 移除了 mutations,直接用 actions 处理同步和异步,更符合直觉,代码量也更少。

第二,TypeScript 支持

Pinia 天然为 TypeScript 设计,定义 store 时自动推断类型,不需要额外标注;Vuex 4 虽然支持 TS,但写法繁琐,需要定义大量类型模板。

第三,API 风格

Pinia 支持组合式 API 风格的 store 定义(类似 Vue 3 的 setup),也支持选项式 API,灵活性更高;Vuex 主要是选项式风格,通过 mapStatemapActions 等辅助函数在组件中使用。

第四,模块化

Vuex 通过 modules 实现模块化,但模块之间嵌套复杂,命名空间需要手动配置;Pinia 每个 store 天然就是独立模块,按需导入,不需要嵌套,代码分割更友好。

第五,体积和性能

Pinia 更轻量,体积比 Vuex 小很多,且利用了 Vue 3 的响应式系统,性能更好。Vuex 4 为了兼容 Vue 2 保留了部分旧机制,体积和性能都不如 Pinia。

迁移建议

  • 新项目直接用 Pinia
  • Vue 2 项目如果要用 Pinia 需要配合 @vue/composition-api 插件,但官方更建议 Vue 2 继续用 Vuex 3
  • Vue 3 项目从 Vuex 迁移到 Pinia 成本较低,API 改动不大

二、20 秒极简版

Pinia 是 Vue 3 官方推荐的状态管理库,相比 Vuex 更轻量、TS 支持更好、API 更简洁。核心区别:Pinia 没有 mutations,直接 actions 处理同步异步;每个 store 独立模块;天然组合式 API 风格。新项目用 Pinia,Vue 2 项目继续用 Vuex 3。

三、五维度对比表

维度VuexPinia
设计理念mutations + actions移除 mutations,actions 处理同步/异步
TypeScript支持但繁琐天然友好,类型自动推断
API 风格选项式 + mapState/mapActions组合式 + 选项式
模块化modules 嵌套,需手动命名空间每个 store 独立模块
体积性能较大,保留 Vue 2 兼容机制更轻量,性能更好

四、追问 1:Pinia 为什么移除了 mutations?

官方移除 mutations 主要基于三点考虑:

第一,mutations 的本质是约束,但实际开发中很多人直接在 actions 里修改状态,mutations 变成了一层"形式主义"的封装,反而增加了样板代码

第二,Vue 3 的响应式系统更强大,Pinia 的 state 本身就是响应式对象,通过 store.count++ 直接修改也能被追踪。Vuex 的 mutations 设计主要是为了配合 Vue 2 的响应式限制和 DevTools 追踪,Vue 3 下这些限制不再成立。

第三,TypeScript 推断更简单,没有 mutations 层后,类型定义大幅简化。

会不会有问题? 实际上不会。Pinia 仍然通过 $patch 提供批量更新,DevTools 对直接修改的追踪能力也很完善。如果团队需要强制"不允许直接修改状态",可以通过约定或 lint 规则控制,而不是框架强制。

五、追问 2:Pinia 中怎么实现模块化?

Pinia 的模块化比 Vuex 简单得多:每个 store 就是独立的模块,不需要嵌套配置。

JavaScript
// stores/user.js
export const useUserStore = defineStore('user', {
  state: () => ({ name: '', token: '' }),
  actions: { logout() { this.token = '' } }
})

// stores/cart.js
export const useCartStore = defineStore('cart', {
  state: () => ({ items: [] }),
  actions: {
    checkout() {
      const userStore = useUserStore()  // 直接引入其他 store
      if (!userStore.token) throw new Error('未登录')
      // 结算逻辑
    }
  }
})

关键点

  • 模块之间互相引用时,直接在 action 或 getter 里调用 useXxxStore() 即可
  • 注意避免循环依赖,如果出现可以拆分为更细粒度的 store
  • Pinia 会自动处理跨 store 的响应性,一个 store 的变化可以触发另一个 store 的 computed 重新计算

六、追问 3:Vuex 4 和 Pinia 在 Vue 3 项目中怎么选?

建议:新项目无脑上 Pinia,老项目迁移看情况

选 Pinia 的理由

  • 代码量减少 30-50%,开发效率高
  • TypeScript 体验碾压 Vuex 4,几乎不需要写类型声明
  • 体积更小,性能更好
  • 官方钦定的下一代方案,社区生态已经全面转向
  • 学习成本低,不需要理解 mutations 和 actions 的区别

继续用 Vuex 4 的场景

  • 老项目已经大量使用 Vuex,迁移成本高,且短期内不会重构
  • 团队对 Vuex 非常熟悉,暂时不想引入新概念
  • 使用了 Vuex 特有的插件生态(部分插件可能还没迁移到 Pinia)

迁移要点

如果是从 Vuex 迁移到 Pinia,官方提供了迁移指南,API 层面的改动主要是:

  • state 写法微调
  • mutations 合并到 actions
  • 模块拆分为独立 store
  • mapState 等辅助函数替换为 storeToRefs

七、易错点

  • 说"Pinia 是 Vuex 5":严格来说 Pinia 不是 Vuex 5,官方曾有过将 Pinia 作为 Vuex 5 候选方案,但最终决定独立发展。能说出"Pinia 可以理解为 Vuex 5 的设计理念继承者"会更准确
  • 认为 Pinia 只支持 Vue 3:Pinia 也支持 Vue 2(需配合 @vue/composition-api),只是 Vue 2 场景下更推荐 Vuex 3
  • 混淆 mutations 和 actions 的本质区别:说"mutations 是同步,actions 是异步"只对了一半。能补充"mutations 用于追踪状态变更,actions 可以包含任意异步操作,但最终还是要 commit mutations"才完整
  • Pinia 的 TypeScript 优势说不清楚:只说"TS 支持好",但说不出"定义 store 时自动推断 state、getters、actions 类型,不需要额外泛型"这种细节
  • 模块化对比只说"Pinia 不用 modules":要说明 Pinia 通过"每个 store 独立文件 + 互相导入"实现模块化
  • 忽略 storeToRefs:Pinia 中解构 store 会丢失响应性,需要用 storeToRefs 包装
  • 迁移建议过于绝对:说"所有项目都应该用 Pinia"不考虑 Vue 2 场景和迁移成本

八、关联文档