从设计理念、TypeScript 支持、开发体验和工程实践四个方面,深入分析 Pinia 为什么会成为 Vue3 官方推荐的状态管理方案。
前言
如果你是从 Vue2 时代一路走过来的开发者,对 Vuex 一定不会陌生。
曾经,Vuex 几乎是每个 Vue 项目的标配。从后台管理系统到企业级 SaaS,再到电商平台,只要涉及多个页面共享数据,大家首先想到的就是 Vuex。
然而到了 Vue3 时代,一个新的名字开始频繁出现在官方文档和开源项目中——Pinia。
如今,无论是 Vue 官方文档、Vite 模板,还是 Element Plus 官方示例,都默认推荐 Pinia,而 Vuex 已经很少出现在新项目中。
那么问题来了:
- Vuex 做错了吗?
- Pinia 到底比 Vuex 好在哪里?
- 老项目还有必要继续使用 Vuex 吗?
本文不会简单对比 API,而是从设计思想和工程实践的角度,分析为什么越来越多团队开始全面转向 Pinia。
Vuex 在 Vue2 时代为什么会成功?
Vuex 出现时,Vue 最大的问题并不是组件开发,而是状态共享。
假设一个后台管理系统中有:
- 用户头像
- 登录状态
- 权限信息
- 当前主题
- 当前语言
这些数据需要 Header、菜单、个人中心、多个页面共同使用。
如果全部依赖 Props 一层层传递,很快就会出现著名的 Props Drilling(属性穿透) 问题。
Vuex 的出现,就是为了提供一个统一的数据中心。
它把所有共享状态放到一个 Store 中,任何组件都可以直接访问,大大降低了组件之间的耦合。
对于当时的大型项目来说,这是一个非常优秀的解决方案。
Vuex 最大的问题是什么?
Vuex 最大的问题不是功能少,而是过于复杂。
以修改用户信息为例,在 Vuex 中通常需要经历这样的流程:
Component
↓
dispatch()
↓
Action
↓
commit()
↓
Mutation
↓
State
如果只是修改一个简单字段,却需要定义 Action、Mutation、常量甚至类型声明。
当项目越来越大时,这些样板代码会越来越多。
很多团队发现,真正的业务代码可能只有几行,而为了配合 Vuex,却要写几十行模板代码。
这种开发体验,在 Vue3 时代已经显得有些笨重。
Vue3 为什么需要 Pinia?
Vue3 最大的变化之一,就是 Composition API。
以前开发 Vue,主要依赖:
- data
- methods
- computed
现在更多写的是:
- ref
- reactive
- computed
- composables
整个开发模式已经更加接近普通 JavaScript。
Pinia 正是围绕这种新的开发方式设计的。
它希望开发者操作 Store 时,能够像操作普通对象一样自然,而不是学习另一套复杂的数据流。
例如:
Vuex:
dispatch()
↓
commit()
↓
Mutation
Pinia:
store.user = data
直接修改状态即可。
这也是很多开发者第一次使用 Pinia 后最大的感受:
简单。
Pinia 真正的优势在哪里?
很多人认为 Pinia 最大的优势只是少写几行代码。
实际上并不是。
它真正的优势来自以下几个方面。
1. API 更符合 JavaScript 思维
Pinia 没有 Mutation,也没有 Commit。
状态就是普通对象。
方法就是普通函数。
学习成本非常低。
对于新加入项目的开发者来说,几乎不用额外学习状态管理框架。
2. TypeScript 支持更加优秀
Pinia 从设计之初就考虑了 TypeScript。
例如:
const userStore = useUserStore()
userStore.user
IDE 可以自动推导:
- 属性类型
- 方法参数
- 返回值
几乎不需要手写类型声明。
相比 Vuex,大幅减少了泛型和模板代码。
如果团队大量使用 TypeScript,这一点优势会非常明显。
3. 更符合模块化开发
Pinia 鼓励一个 Store 负责一个业务。
例如:
stores
├── user.ts
├── order.ts
├── product.ts
或者结合 Feature First:
features
├── user
│ ├── store.ts
│ ├── api.ts
│ ├── types.ts
│ └── components
这样每个业务模块都相对独立,维护起来更加轻松。
Pinia 是否意味着所有状态都应该放进去?
当然不是。
这是很多团队最容易犯的错误。
例如:
- 弹窗是否打开
- 当前 Tab
- 搜索框内容
- 分页页码
这些其实都是页面状态。
更适合:
const visible = ref(false)
而不是:
store.dialogVisible
Pinia 更适合保存:
- 当前登录用户
- Token
- 权限信息
- 系统配置
- 国际化
- 主题设置
也就是说:
真正需要跨页面共享的数据。
如果什么都放 Store,最终只会得到一个越来越庞大的”万能对象”。
企业项目中的最佳实践
在实际项目中,我更推荐下面这种职责划分:
Component
│
▼
Service
│
▼
API
│
▼
Pinia Store
各层职责非常明确:
- Component 负责页面展示
- Service 负责业务逻辑
- API 负责网络请求
- Store 负责保存共享状态
不要在 Store 中直接写大量 axios 请求,也不要在 Store 中操作 Router 或 DOM。
保持 Store 足够简单,后续维护成本会低很多。
Vuex 项目需要迁移吗?
很多团队最关心的问题就是:
老项目是否需要迁移?
我的建议很简单:
不要为了迁移而迁移。
如果你的 Vue2 项目已经稳定运行:
没有必要花大量时间重构。
但是:
如果准备:
- 新建 Vue3 项目
- 使用 Composition API
- 全面采用 TypeScript
那么直接选择 Pinia 会更加合理。
未来 Vue 官方生态的发展方向,也会更多围绕 Pinia 展开。
总结
Pinia 并不是一个”更简单的 Vuex”。
它代表的是 Vue3 整个开发理念的变化。
从复杂的数据流,到更加自然的状态管理;从大量模板代码,到充分利用 TypeScript 类型推导;从统一的大型 Store,到更加灵活的模块化组织方式。
这些变化不仅提升了开发效率,也让现代 Vue 项目更加容易维护。
对于新的 Vue3 项目来说,Pinia 已经不仅仅是官方推荐,更是当前最符合工程实践的状态管理方案。
如果你准备开始一个新的 Vue3 项目,与其继续纠结 Vuex 是否还能使用,不如花一些时间理解 Pinia 背后的设计思想,这比记住几个 API 更有价值。
X记录空间