前言
在前一篇文章中,我们明确了:
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.age
3️⃣ 与 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 对比总结
|
Mutation |
✅ |
❌ |
|
TypeScript |
❌ |
✅ |
|
Composition API |
❌ |
✅ |
|
代码量 |
多 |
少 |
|
学习成本 |
高 |
低 |
九、面试高频问答
Q1:Pinia 为什么去掉 Mutation?
因为 Mutation 增加了不必要的复杂度。
Q2:Pinia 和 Vuex 能共存吗?
可以,但不推荐。
Q3:Pinia 是全局状态还是局部状态?
全局状态,但可按模块拆分。
十、总结
-
Vuex 已完成历史使命
-
Pinia 是 Vue3 状态管理的唯一官方答案
-
更简洁、更类型安全、更 Composable
-
新项目 100% 使用 Pinia
📢 下期预告
👉 第 13 篇:插槽(Slots)完全指南 —— 从匿名插槽到作用域插槽


