Pinia 是 Vue.js 的下一代状态管理库,由 Vue 核心团队维护,专为 Vue 3 设计(同时兼容 Vue 2)。它取代了 Vuex,提供更简洁的 API、完整的 TypeScript 支持,以及更好的开发体验。核心优势包括:轻量级、类型安全、模块化设计,且去除了 mutations 的概念。
核心特性
-
极简 API
- 摒弃了 Vuex 的
mutations
,所有状态修改直接在actions
中完成(支持同步/异步)。 - 减少模板代码,提升开发效率。
- 摒弃了 Vuex 的
-
TypeScript 优先
- 原生支持 TypeScript,提供完整的类型推断,无需额外配置。
-
模块化(Store 独立)
- 每个 Store 是独立实体,无需嵌套模块,天然支持代码分割。
-
Composition API 友好
- 与 Vue 3 的 Composition API 完美融合,可直接在 Store 中使用
ref
、computed
等。
- 与 Vue 3 的 Composition API 完美融合,可直接在 Store 中使用
-
DevTools 集成
- 支持 Vue DevTools 的时间旅行调试(state 修改记录追踪)。
核心概念
1. Store (存储)
Pinia 的核心单元,包含状态、计算属性和方法。
// stores/counter.ts
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }), // 初始状态
actions: {
increment() {
this.count++; // 直接修改状态(无需 mutations)
},
async fetchData() {
const data = await api.getData(); // 异步操作
this.count = data.value;
}
},
getters: {
doubleCount: (state) => state.count * 2, // 计算属性
}
});
2. State
- 使用函数返回初始状态(类似组件
setup()
)。 - 通过
store.$state
访问原始状态对象。
3. Getters
- 相当于 Store 的“计算属性”。
- 可通过
this
访问整个 Store 实例。
4. Actions
- 代替 Vuex 的
mutations
+actions
。 - 可直接修改
state
,支持异步操作。
使用示例
在组件中使用 Store
<script setup>
import { useCounterStore } from '@/stores/counter';
const counter = useCounterStore();
// 直接访问状态
console.log(counter.count);
// 调用 action
counter.increment();
// 使用 getter
console.log(counter.doubleCount);
</script>
<template>
<button @click="counter.increment">{{ counter.count }}</button>
</template>
响应式解构
使用 storeToRefs()
保持响应式:
import { storeToRefs } from 'pinia';
const counter = useCounterStore();
const { count, doubleCount } = storeToRefs(counter); // 保持响应性
进阶用法
1. 插件系统
可扩展 Pinia 功能(如持久化存储):
// 示例:状态持久化插件
const pinia = createPinia();
pinia.use(({ store }) => {
const savedState = localStorage.getItem(store.$id);
if (savedState) store.$patch(JSON.parse(savedState));
store.$subscribe((_, state) => {
localStorage.setItem(store.$id, JSON.stringify(state));
});
});
2. 跨 Store 调用
直接导入其他 Store 使用:
// stores/user.ts
import { useCounterStore } from './counter';
export const useUserStore = defineStore('user', {
actions: {
syncAction() {
const counter = useCounterStore();
counter.increment(); // 调用其他 Store 的 action
}
}
});
3. 热更新支持
Vite 中无需配置,Webpack 需少量代码:
if (import.meta.hot) {
import.meta.hot.accept(['./stores/counter'], () => {
pinia._p.forEach(store => store.$hotUpdate(import.meta.hot));
});
}
对比 Vuex
特性 | Pinia | Vuex |
---|---|---|
API 复杂度 | 极简(无 mutations) | 较复杂(mutations/actions) |
TypeScript | 原生支持 | 需额外类型定义 |
模块化 | 天然扁平化 | 嵌套模块 |
包大小 | ~1KB | ~4KB |
Composition API | 原生适配 | 需额外插件 |
最佳实践
- Store 命名:使用
useXxxStore
格式(如useUserStore
)。 - 状态初始化:始终用函数返回
state
避免共享状态污染。 - 修改状态:优先用
$patch
批量更新:counter.$patch({ count: counter.count + 1 }); // 或函数形式 counter.$patch((state) => state.items.push(newItem));
- 重置状态:
counter.$reset()
恢复初始值。 - SSR 支持:通过
pinia.use(createPinia())
集成到服务端渲染。
生态工具
- 官方插件:
@pinia/nuxt
:Nuxt.js 集成@pinia/testing
:单元测试工具
- 社区插件:
pinia-plugin-persistedstate
:状态持久化pinia-orm
:ORM 式数据管理
总结
Pinia 凭借其简洁性、类型安全和开发体验优化,已成为 Vue 状态管理的首选。它解决了 Vuex 的冗余设计,同时完美契合 Vue 3 的响应式系统和 Composition API。对于新项目,强烈推荐使用 Pinia;老项目迁移也只需少量改动。
官方文档:pinia.vuejs.org