vue3 中的pinia和vue2中的vuex的区别
一、先说结论:它俩到底啥关系?
打个比方:
- Vuex 是 Vue 2 时代的"老管家",规矩多、流程复杂,但是很全能。
- Pinia 是 Vue 3 时代的"新管家",是 Vue 官方现在推荐的默认状态管理方案(Vuex 4 虽然能用,但官方态度已经是"新项目用 Pinia")。
一句话总结核心差别:Pinia 把 Vuex 里最繁琐的部分删掉了,剩下的都是精华。
二、核心概念:5 个变 3 个
这是两者最直观的区别。Vuex 一套流程要记 5 个概念,Pinia 只留 3 个:
|
概念
|
Vuex
|
Pinia
|
说明
|
|
state(数据)
|
✅
|
✅
|
状态数据,两边都有
|
|
getters(计算属性)
|
✅
|
✅
|
派生的数据,两边都有
|
|
mutations(同步修改)
|
✅
|
❌ 删掉了
|
Pinia 里不需要
|
|
actions(异步操作)
|
✅
|
✅
|
但 Pinia 的 actions 更强大
|
|
modules(模块)
|
✅
|
❌ 删掉了
|
Pinia 天然就是模块化的
|
最大的变化就是 mutations 没了。
三、最关键的改变:mutations 为什么被"开掉"了?
在 Vuex 里,改数据有一条铁律:
同步修改必须走 mutations,异步操作必须先走 actions,再在 actions 里 commit 给 mutations。
所以写一个异步改数据的操作,你要绕一大圈:
// ===== Vuex 写法:一改数据要过两道门 ===== // 1. mutations:只负责同步改 mutations: { setCount(state, n) { state.count = n } }, // 2. actions:负责异步,再转交给 mutations actions: { async fetchCount({ commit }) { const data = await api.get() commit('setCount', data) // 转一道手 } } // 3. 组件里调用 this.$store.dispatch('fetchCount')
而 Pinia 直接"一个 actions 搞定",同步异步都能直接改:
// ===== Pinia 写法:一步到位 ===== export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { async fetchCount() { this.count = await api.get() // 直接改,不转手 } } }) // 组件里调用 counterStore.fetchCount()
大白话解释:Vuex 是"改数据要先过两道安检",Pinia 是"直接改,但依然能追踪"。少了一道繁琐的流程,代码量直接减半,对新手友好太多。
四、模块化:从"套娃"到"自由"
这是第二个大差异。
Vuex 用 modules 嵌套,还要写 namespaced: true 来防止命名冲突,一旦模块多了就像套娃,找东西很费劲:
// ===== Vuex:要注册模块 + 命名空间 ===== export default new Vuex.Store({ modules: { user: userModule, // 得手动挂载 cart: { namespaced: true, ... } // 还得设命名空间 } }) // 组件里调用还要写全路径 this.$store.commit('cart/addItem', item)
Pinia 不需要 modules,每个 store 本身就是独立的"文件",谁要用谁引入,清爽自然:
// ===== Pinia:每个 store 自己独立,不用挂载 ===== // user.js export const useUserStore = defineStore('user', { ... }) // cart.js export const useCartStore = defineStore('cart', { ... }) // 组件里直接用 const userStore = useUserStore() const cartStore = useCartStore()
大白话解释:Vuex 是"一个大柜子,所有东西塞进去,还要贴标签防止撞名";Pinia 是"每人一个独立抽屉,各自管各自",没有命名空间烦恼,代码更好维护。
五、TypeScript 支持:Pinia 完胜
这一点对工程化项目尤其重要。
- Vuex 在 TS 下:要写一堆类型定义、namespace、模块类型,用起来很繁琐,经常要"类型体操"。
- Pinia 在 TS 下:类型推断非常友好,几乎零配置,IDE 提示也准。它本身就用 TS 写的,天生为 TS 设计。
如果你是用 TS 写 Vue3 项目,Pinia 几乎是必然选择。
六、组件里怎么用:一个更顺手
Vuex 需要靠 this.$store 或者 useStore(),访问要带 state. / getters. 前缀,修改要 commit,异步要 dispatch,记的东西多:
// Vuex 组件里 this.$store.state.count this.$store.getters.doubleCount this.$store.commit('setCount', 10) this.$store.dispatch('fetchCount')
Pinia 直接解构使用,跟操作普通对象一样,还专门提供了 storeToRefs 保持响应性:
// Pinia 组件里 const counterStore = useCounterStore() const { count } = storeToRefs(counterStore) // 保持响应式 counterStore.count = 10 // 直接赋值修改 counterStore.fetchCount()
七、一张表速览所有区别
|
对比项
|
Vuex
|
Pinia
|
|
适用版本
|
Vue 2 / Vue 3(Vuex 4)
|
Vue 3(重点)
|
|
官方定位
|
旧版默认
|
当前官方推荐
|
|
核心概念
|
state/getters/mutations/actions/modules
|
state/getters/actions
|
|
mutations
|
必须有
|
已移除
|
|
异步改状态
|
actions → commit mutations
|
actions 直接改
|
|
模块化
|
modules 嵌套 + 命名空间
|
多 store 独立
|
|
TypeScript
|
支持但繁琐
|
原生友好
|
|
代码量
|
多
|
少(约少一半)
|
|
组合式 API
|
支持一般
|
完全适配
|
|
体积
|
较大
|
更轻量
|
八、我该选哪个?给个直接的建议
- 新项目用 Vue3 → 直接用 Pinia,官方推荐,代码简洁,别再纠结。
- 老项目用 Vue2 → 继续用 Vuex,没必要动,稳定为王。
- 老项目从 Vue2 迁 Vue3 → 建议顺手迁到 Pinia,改动其实不大(主要是去掉 mutations、去掉 modules)。
九、一个比喻帮你记牢
把状态管理想象成管理家里的物品:
- Vuex:所有东西放一个总仓库,拿东西要填"申请单"(commit)、要派人去取(dispatch),分门别类还得挂标签(namespaced)。规矩多,但把安全做到了极致。
- Pinia:每个房间自己管自己的东西,开门就能拿,放下就能改,但记录依然清楚。简单直接,又不失控。
一句话:Vuex 教会了我们"怎么管状态",Pinia 让我们"更轻松地管状态"。 如果是从零开始,直接拥抱 Pinia 就对了。
浙公网安备 33010602011771号