Vuex 和 Pinia 都是 Vue 生态中的状态管理库,但它们的定位和设计理念有本质区别。Pinia 是 Vue 官方目前推荐的状态管理方案,Vuex 已进入维护模式,不再适用于新项目。
📦 Vuex:传统的集中式状态管理
Vuex 是 Vue 2 时代官方推荐的状态管理库,遵循 Flux 架构,采用严格的单向数据流,专为大型复杂应用设计,以确保状态变化的可预测性。
核心概念:
· State:单一状态树,存放所有共享数据。
· Getters:从 State 派生数据,类似计算属性。
· Mutations:唯一可以同步修改 State 的地方。
· Actions:处理异步逻辑,通过 commit 触发 Mutation 间接更新状态。
· Modules:将 Store 分割成模块,通过命名空间管理。
Vuex 的严格规范在大型团队中有利于代码规范,但也带来了大量样板代码和复杂的 TypeScript 类型声明等问题。
🌿 Pinia:Vue 3 的现代化状态管理
Pinia 由 Vue 核心团队成员开发,最初被称为 "Vuex 5",但并非 Vuex 的升级版,而是从设计理念上就不同的替代方案。它深度整合 Vue 3 的 Composition API 和响应式系统,API 极其简洁。
核心概念:
· State:使用函数返回初始状态,更符合 Vue 3 风格。
· Getters:类似 Vue 的计算属性,写法更直观。
· Actions:取消了 Mutations,可以直接修改 State,同时支持同步和异步操作。
📊 核心差异对比
对比维度 Vuex Pinia
API 设计 复杂,需区分 Mutations/Actions 极简,无 Mutations,Actions 直接改 State
TypeScript 支持 需大量手写类型声明,体验较差 开箱即用的完整类型推导,IDE 自动补全精准
模块化 单一 Store 树,嵌套 Modules,访问路径冗长 多 Store 设计,独立定义,可互相 import 引用
体积 稍大 约 1.5kb,极其轻量
代码量 样板代码多 通常减少 30%--50%
Vue 版本 支持 Vue 2 和 Vue 3 专为 Vue 3 设计,也支持 Vue 2
官方定位 维护模式,不推荐用于新代码 官方默认推荐的状态管理方案
🎯 如何选择?
新项目:直接选择 Pinia。它是 Vue 官方推荐,API 简洁、TS 体验优秀、体积小巧,是当前 Vue 3 生态的绝对主流。
存量 Vuex 项目:不必急于全量迁移,可采用渐进式迁移------新功能用 Pinia 开发,旧模块在维护中逐步迁移;也可通过"桥接 Store"让两者共存,优先迁移用户信息、权限等核心状态。
仅需简单状态共享:如果应用只有两三个页面,使用 Vue 3 自身的 ref/reactive 配合 provide/inject 即可,无需引入任何状态管理库。
💎 总结
Pinia 并非 Vuex 的简单升级,而是一次设计理念的革新------用更少的 API、更好的类型支持、更自然的模块化,解决了 Vuex 长期存在的样板代码多、TS 体验差、模块嵌套复杂等痛点。对于 2026 年的 Vue 开发者而言,Pinia 已是默认选择,Vuex 则属于需要维护的历史项目。
下面分别对 Vuex 和 Pinia 做详细拆解,包括设计思想、核心概念、代码示例、优缺点和适用场景。
一、Vuex 详解
- 是什么
Vuex 是 Vue 2 时代官方推荐的状态管理库,受 Flux、Redux 启发,采用集中式存储管理组件间共享状态,并通过一套规则保证状态变化可预测、可追踪。
Vuex 4 适配 Vue 3,Vuex 3 适配 Vue 2。目前 Vuex 已进入维护模式,官方不再推荐用于新项目。
- 核心思想
· 单一状态树:整个应用只有一个 Store,所有共享状态集中存放。
· 单向数据流:组件不能直接修改 State,必须通过 Mutation。
· 严格同步:Mutation 必须同步,异步逻辑放在 Action 中。
- 核心概念
概念 作用 特点
State 存储共享数据 单一状态树,唯一数据源
Getters 从 State 派生数据 类似计算属性,可缓存
Mutations 修改 State 的唯一方式 必须同步,通过 commit 触发
Actions 处理异步逻辑 通过 dispatch 触发,内部 commit Mutation
Modules 拆分 Store 可命名空间隔离,避免冲突
-
工作流程
组件 dispatch Action
↓
Action 执行异步操作
↓
Action commit Mutation
↓
Mutation 同步修改 State
↓
State 更新,组件重新渲染 -
代码示例
创建 Store:
js
// store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
count: 0
},
getters: {
doubleCount: (state) => state.count * 2
},
mutations: {
INCREMENT(state, payload) {
state.count += payload
}
},
actions: {
incrementAsync({ commit }, payload) {
setTimeout(() => {
commit('INCREMENT', payload)
}, 1000)
}
},
modules: {
// 模块化
}
})
组件中使用:
vue
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
const store = useStore()
const count = computed(() => store.state.count)
const doubleCount = computed(() => store.getters.doubleCount)
const increment = () => store.commit('INCREMENT', 1)
const incrementAsync = () => store.dispatch('incrementAsync', 1)
</script>
- TypeScript 支持
Vuex 的 TS 支持较弱,需要手动声明类型:
ts
// 需要定义 InjectionKey、State 类型、模块类型等
const store = useStore<State>()
模块嵌套后类型推导复杂,通常需要大量手写类型声明。
- 优缺点
优点:
· 规范严格,状态变更可追踪
· DevTools 支持时间旅行
· 生态成熟,适合大型团队协作
· 模块化支持命名空间
缺点:
· 样板代码多,概念多
· 必须区分 Mutation 和 Action
· TypeScript 体验差
· 模块嵌套复杂,访问路径冗长
· 体积较大
- 适用场景
· Vue 2 老项目
· 已使用 Vuex 的存量项目维护
· 需要严格状态追踪的大型应用
· 团队已熟悉 Vuex 规范
二、Pinia 详解
- 是什么
Pinia 是 Vue 官方目前推荐的状态管理库,由 Vue 核心团队成员开发,最初被称为 "Vuex 5",但设计理念完全不同。它深度整合 Vue 3 的 Composition API,API 极简,TypeScript 支持极佳。
Pinia 支持 Vue 2 和 Vue 3,但主要面向 Vue 3。
- 核心特点
· 无 Mutations:只有 State、Getters、Actions
· Actions 可直接修改 State:同步异步都支持
· 多 Store 设计:每个 Store 独立,可互相引用
· 完整 TypeScript 类型推导:开箱即用
· 极轻量:约 1.5kb
· DevTools 支持:时间旅行、热更新
· 插件系统:持久化、日志等
- 核心概念
概念 作用 特点
Store 独立的状态容器 通过 defineStore 定义
State 存储数据 可直接修改
Getters 派生数据 类似计算属性
Actions 业务逻辑 同步/异步均可,直接改 State
- 两种定义方式
选项式 Store:
js
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment(payload) {
this.count += payload
},
async incrementAsync(payload) {
await new Promise((r) => setTimeout(r, 1000))
this.increment(payload)
}
}
})
组合式 Store(推荐):
js
// stores/counter.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment(payload) {
count.value += payload
}
async function incrementAsync(payload) {
await new Promise((r) => setTimeout(r, 1000))
increment(payload)
}
return { count, doubleCount, increment, incrementAsync }
})
- 组件中使用
vue
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
// 解构 state 和 getters 并保持响应性
const { count, doubleCount } = storeToRefs(counter)
// actions 可以直接解构
const { increment, incrementAsync } = counter
</script>
<template>
<p>count: {{ count }}</p>
<p>double: {{ doubleCount }}</p>
<button @click="increment(1)">+1</button>
<button @click="incrementAsync(1)">异步 +1</button>
</template>
- 常用 API
· $patch:批量修改 State
js
counter.$patch({ count: 10 })
counter.$patch((state) => { state.count = 10 })
· $reset:重置 State
· 选项式 Store 自带
· 组合式 Store 需手动实现
· $subscribe:监听 State 变化
js
counter.$subscribe((mutation, state) => {
console.log(state.count)
})
· $onAction:监听 Action 调用
js
counter.$onAction(({ name, args, after, onError }) => {
console.log(`Action ${name} 被调用`)
})
- 模块化与互相引用
每个 Store 独立文件,直接 import 即可:
js
// stores/user.js
import { defineStore } from 'pinia'
import { useCartStore } from './cart'
export const useUserStore = defineStore('user', () => {
const cart = useCartStore()
function checkout() {
cart.clear()
}
return { checkout }
})
- TypeScript 支持
Pinia 自动推导类型,无需额外声明:
ts
const counter = useCounterStore()
counter.count // number
counter.increment(1) // 参数类型自动推导
- 优缺点
优点:
· API 极简,学习成本低
· TypeScript 体验极佳
· 模块化自然,多 Store 独立
· 轻量,体积小
· 官方推荐,生态活跃
· DevTools 支持完善
缺点:
· 从 Vuex 迁移需要一定成本
· 部分旧插件只支持 Vuex
· 组合式 Store 的 $reset 需手动实现
- 适用场景
· Vue 3 新项目
· TypeScript 项目
· 中小型到大型应用
· 希望代码简洁、类型安全的团队
三、总结对比
维度 Vuex Pinia
官方定位 维护模式 官方推荐
API 风格 复杂,Mutations + Actions 极简,只有 Actions
修改 State 必须通过 Mutation 可直接修改
TypeScript 需手动声明 自动推导
模块化 嵌套 Modules 多 Store 独立
体积 较大 约 1.5kb
学习成本 较高 较低
适用项目 Vue 2 老项目 Vue 3 新项目
选择建议:
· 新项目:直接用 Pinia
· 老项目:渐进式迁移,新功能用 Pinia,旧模块逐步替换
· 简单共享状态:ref/reactive + provide/inject 即可,无需状态管理库
Pinia 已成为 Vue 3 生态的事实标准,Vuex 则属于需要维护的历史方案。