《Vue3 从入门到大神12篇》组件通信全景图(下)—— Vuex 到 Pinia 的华丽转身
前言
在前一篇文章中,我们明确了:
Event Bus 已死,Props / Emit / Provide-Inject 各有边界。
但还有一个问题没有解决:
❓ 真正的全局状态应该放在哪里?
Vue2 时代,答案是Vuex。
Vue3 时代,官方给出的答案是:
✅Pinia
这一篇,我们就来讲清楚:
Pinia 到底是什么?
它如何取代 Vuex?
State / Getter / Action 怎么用?
为什么它更适合 Composition API?
一、Vuex 的历史地位与痛点
1️⃣ Vuex 解决了什么问题?
✅ 集中式状态管理
✅ 可预测的数据流
✅ DevTools 支持
2️⃣ 但 Vuex 也有明显痛点
痛点 | 说明 |
|---|---|
概念太多 | State / Getter / Mutation / Action |
修改状态繁琐 | 必须 commit mutation |
TypeScript 支持差 | 类型推导极其痛苦 |
代码冗长 | 一个简单的状态改动要写很多样板代码 |
📌一句话总结:
Vuex 是为 Vue2 设计的,不是为 Composition API 设计的。
二、Pinia 是什么?
官方定义:
Pinia 是 Vue 的官方状态管理库,是 Vuex 的继任者。
它的设计目标非常明确:
✅ 更简单
✅ 更直观
✅ 更好的 TypeScript 支持
✅ 更贴合 Composition API
三、Pinia 核心概念(State / Getter / Action)
1️⃣ 定义一个 Store
// stores/user.ts import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ name: 'Tom', age: 18 }), getters: { doubleAge: (state) => state.age * 2 }, actions: { growUp() { this.age++ } } })📌对比 Vuex:
❌ 没有 mutation
✅ 只有 state / getter / action
四、在组件中使用 Pinia
1️⃣ 安装 Pinia
// main.ts import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' createApp(App) .use(createPinia()) .mount('#app')2️⃣ 使用 Store
<script setup lang="ts"> import { useUserStore } from '@/stores/user' const userStore = useUserStore() </script> <template> <div> <p>{{ userStore.name }}</p> <p>{{ userStore.doubleAge }}</p> <button @click="userStore.growUp">长大</button> </div> </template>✅像使用普通对象一样使用状态
五、为什么 Pinia 能取代 Vuex?
1️⃣ 去掉了 Mutation
Vuex:
commit('increment')Pinia:
store.increment()📌结论:
Mutation 是冗余设计。
2️⃣ 天然支持 TypeScript
const store = useUserStore() store.age // ✅ 类型提示Vuex 需要:
(this as any).$store.state.user.age3️⃣ 与 Composition API 完美融合
export function useUser() { const store = useUserStore() return { ...store } }✅Pinia 本身就是 Composable 风格
六、Pinia 的响应式与解构
❌ 错误用法
const { name } = userStore👉 会失去响应式
✅ 正确用法
import { storeToRefs } from 'pinia' const { name } = storeToRefs(userStore)七、Pinia 的高级能力
1️⃣ 模块化(天生支持)
stores/ ├── user.ts ├── cart.ts └── product.ts✅无需 namespace
2️⃣ 组合式写法(推荐 ✅)
export const useUserStore = defineStore('user', () => { const name = ref('Tom') const age = ref(18) const doubleAge = computed(() => age.value * 2) const growUp = () => age.value++ return { name, age, doubleAge, growUp } })📌这是 Pinia 的终极形态。
八、Pinia vs Vuex 对比总结
对比项 | Vuex | Pinia |
|---|---|---|
Mutation | ✅ | ❌ |
TypeScript | ❌ | ✅ |
Composition API | ❌ | ✅ |
代码量 | 多 | 少 |
学习成本 | 高 | 低 |
九、面试高频问答
Q1:Pinia 为什么去掉 Mutation?
因为 Mutation 增加了不必要的复杂度。
Q2:Pinia 和 Vuex 能共存吗?
可以,但不推荐。
Q3:Pinia 是全局状态还是局部状态?
全局状态,但可按模块拆分。
十、总结
Vuex 已完成历史使命
Pinia 是 Vue3 状态管理的唯一官方答案
更简洁、更类型安全、更 Composable
新项目100% 使用 Pinia
📢 下期预告
👉第 13 篇:插槽(Slots)完全指南 —— 从匿名插槽到作用域插槽
