Pinia 技术文档
(一)一、概述
Pinia 是 Vue.js 生态中下一代状态管理库,由 Vue 核心团队成员开发,可视为 Vuex 的进化版。它通过更简洁的 API、一流的 TypeScript 支持和灵活的模块化设计,为 Vue 应用(Vue 2/3)提供了高效的全局状态管理解决方案,尤其适用于中大型项目的状态管理需求。
(二)二、核心概念
Pinia 的核心模型由 Store(仓库) 驱动,每个 Store 包含状态(State)、计算属性(Getters)和操作方法(Actions)三个核心部分,共同管理全局状态。
1.1. Store(仓库)
Store 是 Pinia 的核心容器,用于存储和管理全局状态。通过 defineStore 函数创建,需指定唯一的 Store ID(用于 DevTools 调试)。
示例:基础 Store 结构
// 定义一个计数器 Store
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }), // 状态(数据)
getters: { double: (state) => state.count * 2 }, // 计算属性
actions: { increment() { this.count++ } } // 操作方法
});
2.2. State(状态)
State 是 Store 中的响应式数据源,类似组件中的 data,用于存储全局共享的数据(如用户信息、购物车列表等)。
• 特性:
– 响应式:基于 Vue 的 ref/reactive 实现,状态变更会触发组件重新渲染;
– 可直接修改:无需通过 mutations(对比 Vuex),通过 this.xxx = value 直接更新;
– 支持复杂类型:如对象、数组等。
示例:用户信息 State
state: () => ({
user: null as User | null, // 用户对象(初始为 null)
cartItems: [] as CartItem[], // 购物车列表
token: localStorage.getItem('token') || '' // 登录令牌
})
3.3. Actions(操作方法)
Actions 是 Store 中修改状态的逻辑封装,支持同步或异步操作,取代了 Vuex 中的 mutations 和 actions。
• 特性:
– 直接修改 State:通过 this.xxx = value 直接更新状态;
– 支持异步:可使用 async/await 处理 API 请求;
– 可组合其他 Store:在 Action 中调用其他 Store 的方法。
示例:登录操作(含异步请求)
actions: {
async login(credentials: { email: string; password: string }) {
const res = await api.login(credentials); // 调用 API 登录
this.user = res.data; // 直接更新用户状态
this.token = res.token; // 更新令牌
localStorage.setItem('token', res.token); // 本地存储令牌
}
}
4.4. Getters(计算属性)
Getters 是基于 State 的派生数据,类似 Vue 组件中的 computed,用于计算或过滤状态,结果会自动缓存(仅当依赖的 State 变化时重新计算)。
示例:购物车总金额计算
getters: {
cartTotal: (state) => state.cartItems.reduce((sum, item) => sum + item.price, 0)
}
(三)三、关键特性
1.1. TypeScript 优先支持
Pinia 内置完整的类型推断,无需额外配置即可自动推导 State、Getters 和 Actions 的类型,显著提升开发体验和代码健壮性。
示例:类型自动推断
const counter = useCounterStore();
counter.count; // 自动推断为 number 类型
counter.double; // 自动推断为 number 类型(基于 getters)
counter.increment(); // 自动推断为 void 类型(无返回值)
2.2. Composition API 友好
Pinia 与 Vue 的 Composition API 深度集成,支持在 setup 函数中直接使用 Store,并通过 storeToRefs 解构保持响应性。
示例:组件中使用 Store
<script setup>
import { useUserStore } from '@/stores/user';
import { storeToRefs } from 'pinia';
const userStore = useUserStore();
// 解构 State 并保持响应性(需使用 storeToRefs)
const { user, isLoggedIn } = storeToRefs(userStore);
</script>
3.3. 模块化架构
Pinia 采用扁平化的 Store 结构,支持按业务模块拆分多个独立 Store(如 user.store.ts、cart.store.ts),避免 Vuex 中嵌套模块的复杂性。
示例:Store 目录结构
src/stores/
├── user.store.ts # 用户状态
├── cart.store.ts # 购物车状态
└── product.store.ts # 商品状态
4.4. DevTools 深度集成
Pinia 与 Vue DevTools 无缝协作,支持:
• 状态变化追踪:实时查看 State、Getters、Actions 的变更记录;
• 时间旅行调试:回滚或重做状态变更;
• Action 日志:记录每个 Action 的入参、执行时间和结果。
5.5. 轻量无冗余
Pinia 核心包仅 ~1KB(gzip),相比 Vuex(~10KB)大幅减少体积。同时移除了 Vuex 中冗余的 mutations 和嵌套模块设计,API 复杂度降低约 60%。
(四)四、对比 Vuex
Pinia 作为 Vuex 的进化版,在多个关键维度上进行了优化:
特性 |
Pinia |
Vuex |
API 复杂度 |
简单(无 commit/dispatch) |
复杂(需 commit/dispatch) |
TypeScript |
自动类型推断 |
需手动定义类型 |
模块系统 |
扁平化 Store |
嵌套 Modules |
代码分割 |
自动按需加载 |
需手动处理 |
状态修改 |
直接修改(this.xxx) |
需通过 mutations |
包大小 |
~1KB (gzip) |
~10KB (gzip) |
(五)五、最佳实践
1.1. 定义用户状态 Store
// stores/user.store.ts
import { defineStore } from 'pinia';
import api from '@/api';
export const useUserStore = defineStore('user', {
state: () => ({
id: null as number | null, // 用户 ID
name: '', // 用户姓名
token: localStorage.getItem('token') || '' // 登录令牌
}),
actions: {
// 登录操作(异步)
async login(credentials: { email: string; password: string }) {
const res = await api.login(credentials);
this.id = res.id;
this.name = res.name;
this.token = res.token;
localStorage.setItem('token', res.token); // 本地存储令牌
},
// 退出登录
logout() {
this.$reset(); // 重置 State(需在定义 Store 时声明初始值)
localStorage.removeItem('token');
}
},
getters: {
// 判断是否登录
isLoggedIn: (state) => !!state.token
}
});
2.2. 组件中使用 Store
<template>
<div v-if="isLoggedIn">
<h1>欢迎,{{ name }}</h1>
<button @click="logout">退出登录</button>
</div>
<div v-else>
<button @click="handleLogin">登录</button>
</div>
</template>
<script setup>
import { useUserStore } from '@/stores/user';
import { storeToRefs } from 'pinia';
const userStore = useUserStore();
// 解构并保持响应性(需使用 storeToRefs)
const { name, isLoggedIn } = storeToRefs(userStore);
// 登录操作
const handleLogin = async () => {
await userStore.login({
email: 'test@example.com',
password: 'secret'
});
};
// 退出登录操作
const logout = () => {
userStore.logout();
};
</script>
(六)六、核心优势
1.1. 直观的 API 设计
Pinia 移除了 Vuex 中冗余的 mutations 和 dispatch,通过 state + actions + getters 直接管理状态,代码量减少约 40%,逻辑更清晰。
2.2. 极佳的类型安全
自动推导 Store 中所有属性和方法的类型,避免因类型错误导致的运行时问题,显著提升大型项目的可维护性。
3.3. 灵活的逻辑组合
支持在一个 Store 中调用其他 Store 的方法,实现状态逻辑的灵活组合(如购物车 Store 调用用户 Store 的登录状态)。
4.4. SSR 友好
Pinia 内置服务端渲染(SSR)支持,通过 pinia-plugin-persistedstate 等插件可轻松实现状态持久化,适配 Nuxt.js 等 SSR 框架。
(七)七、总结
Pinia 是 Vue 生态中推荐的下一代状态管理解决方案,通过简洁的 API、一流的 TypeScript 支持和模块化设计,为 Vue 应用提供了高效、灵活的全局状态管理能力。其核心价值在于:用更少的代码、更直观的方式实现强大的状态管理功能,同时保持出色的类型安全和开发体验,是中大型 Vue 3 项目的首选状态管理库。