娱乐盒子
79.37M · 2026-03-10
在 Vue 生态系统的发展进程中,状态管理方案经历了从 Vuex 到 Pinia 的重要演变。Pinia(发音为 /piːnjə/,类似于英语中的 "pineapple")是 Vue 3 的官方推荐状态管理库,由 Vue 核心团队成员 Posva 开发。它旨在提供比 Vuex 更简洁、更类型安全、更模块化的状态管理体验。
Pinia 去除了 Vuex 中的 mutations 概念,只保留 state、getters 和 actions 三个核心概念,使代码更加直观和易于理解。
Pinia 从一开始就为 TypeScript 设计,无需复杂的配置即可享受完整的类型推断和类型检查功能。
每个 store 都是独立的模块,可以按需导入和使用,避免了 Vuex 中复杂的命名空间配置。
Pinia 的包体积非常小(约 1KB gzipped),对应用性能影响极小。
Pinia 与 Vue 3 的 Composition API 完美集成,同时也支持 Options API。
State 是 store 中的数据源,类似于组件中的 data。
1// stores/counter.js
2import { defineStore } from 'pinia'
3
4export const useCounterStore = defineStore('counter', {
5 state: () => ({
6 count: 0,
7 name: 'Pinia Store'
8 })
9})
Getters 相当于 store 的计算属性,用于派生状态。
1export const useCounterStore = defineStore('counter', {
2 state: () => ({
3 count: 0,
4 price: 10
5 }),
6 getters: {
7 doubleCount: (state) => state.count * 2,
8 totalPrice() {
9 return this.count * this.price
10 }
11 }
12})
Actions 用于处理业务逻辑,可以是同步或异步操作。
1export const useCounterStore = defineStore('counter', {
2 state: () => ({
3 count: 0
4 }),
5 actions: {
6 increment() {
7 this.count++
8 },
9 async fetchCount() {
10 const response = await fetch('/api/count')
11 this.count = await response.json()
12 }
13 }
14})
1npm install pinia
2# 或
3yarn add pinia
4# 或
5pnpm add pinia
1// main.js
2import { createApp } from 'vue'
3import { createPinia } from 'pinia'
4import App from './App.vue'
5
6const app = createApp(App)
7const pinia = createPinia()
8
9app.use(pinia)
10app.mount('#app')
1<script setup>
2import { useCounterStore } from '@/stores/counter'
3import { computed, ref } from 'vue'
4
5const counterStore = useCounterStore()
6
7// 直接访问 state
8console.log(counterStore.count)
9
10// 调用 actions
11counterStore.increment()
12
13// 使用 getters
14const doubleCount = computed(() => counterStore.doubleCount)
15
16// 响应式解构(推荐方式)
17import { storeToRefs } from 'pinia'
18const { count, name } = storeToRefs(counterStore)
19const { increment, fetchCount } = counterStore
20</script>
21
22<template>
23 <div>
24 <p>计数: {{ count }}</p>
25 <p>名称: {{ name }}</p>
26 <p>双倍计数: {{ doubleCount }}</p>
27 <button @click="increment">增加</button>
28 </div>
29</template>
1<script>
2import { useCounterStore } from '@/stores/counter'
3import { mapState, mapActions, mapGetters } from 'pinia'
4
5export default {
6 computed: {
7 ...mapState(useCounterStore, ['count', 'name']),
8 ...mapGetters(useCounterStore, ['doubleCount'])
9 },
10 methods: {
11 ...mapActions(useCounterStore, ['increment', 'fetchCount'])
12 }
13}
14</script>
通过插件实现状态持久化:
1npm install pinia-plugin-persistedstate
1// main.js
2import { createPinia } from 'pinia'
3import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
4
5const pinia = createPinia()
6pinia.use(piniaPluginPersistedstate)
7
8// stores/user.js
9export const useUserStore = defineStore('user', {
10 state: () => ({
11 token: '',
12 userInfo: null
13 }),
14 persist: {
15 key: 'my_user_store',
16 storage: localStorage,
17 paths: ['token'] // 只持久化 token
18 }
19})
可以在一个 store 中使用其他 store:
1export const useCartStore = defineStore('cart', {
2 state: () => ({
3 items: []
4 }),
5 getters: {
6 total() {
7 const productStore = useProductStore()
8 return this.items.reduce((sum, item) => {
9 const product = productStore.products.find(p => p.id === item.productId)
10 return sum + (product?.price || 0) * item.quantity
11 }, 0)
12 }
13 }
14})
1const counterStore = useCounterStore()
2
3// 订阅任何状态变化
4counterStore.$subscribe((mutation, state) => {
5 console.log('状态变化:', mutation)
6 console.log('新状态:', state)
7})
8
9// 特定 action
10counterStore.$onAction(({ name, args, after, onError }) => {
11 after(() => {
12 console.log(`${name} 执行完成`)
13 })
14 onError((error) => {
15 console.error(`${name} 执行失败:`, error)
16 })
17})
| 特性 | Pinia | Vuex |
|---|---|---|
| Mutations | 不需要 | 必需 |
| TypeScript 支持 | 优秀 | ️ 需要额外配置 |
| 模块化 | 原生支持 | ️ 需要命名空间 |
| 包体积 | ~1KB | ~3KB |
| DevTools 支持 | 完整支持 | 完整支持 |
| Vue 3 支持 | 首选 | ️ 兼容但非首选 |
| 热重载 | 支持 | 支持 |
1stores/
2├── user.js
3├── cart.js
4├── products.js
5└── settings.js
1// stores/counter.ts
2import { defineStore } from 'pinia'
3
4interface CounterState {
5 count: number
6 name: string
7}
8
9export const useCounterStore = defineStore('counter', {
10 state: (): CounterState => ({
11 count: 0,
12 name: 'Pinia'
13 }),
14 getters: {
15 doubleCount: (state): number => state.count * 2
16 },
17 actions: {
18 increment(): void {
19 this.count++
20 }
21 }
22})
始终通过 actions 来修改状态,以保持代码的可预测性和可维护性。
只对需要持久化的数据进行配置,避免不必要的存储开销。
Pinia 作为 Vue 3 的官方状态管理解决方案,以其简洁的 API、出色的 TypeScript 支持和现代化的设计理念,成为了 Vue 开发者管理应用状态的首选工具。它不仅解决了 Vuex 中存在的一些痛点,还提供了更好的开发体验和更强大的功能扩展能力。
对于新的 Vue 3 项目,强烈推荐使用 Pinia 进行状态管理。对于现有的 Vuex 项目,也可以考虑逐步迁移到 Pinia,以享受更现代的开发体验。
随着 Vue 生态系统的不断发展,Pinia 也在持续演进,未来将会提供更多实用的功能和优化,成为 Vue 开发者不可或缺的工具之一。