Pinia 简介

4 阅读2分钟

Pinia 是 Vue.js 的下一代状态管理库,由 Vue 核心团队维护,专为 Vue 3 设计(同时兼容 Vue 2)。它取代了 Vuex,提供更简洁的 API、完整的 TypeScript 支持,以及更好的开发体验。核心优势包括:轻量级类型安全模块化设计,且去除了 mutations 的概念


核心特性

  1. 极简 API

    • 摒弃了 Vuex 的 mutations,所有状态修改直接在 actions 中完成(支持同步/异步)。
    • 减少模板代码,提升开发效率。
  2. TypeScript 优先

    • 原生支持 TypeScript,提供完整的类型推断,无需额外配置。
  3. 模块化(Store 独立)

    • 每个 Store 是独立实体,无需嵌套模块,天然支持代码分割。
  4. Composition API 友好

    • 与 Vue 3 的 Composition API 完美融合,可直接在 Store 中使用 refcomputed 等。
  5. 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

特性PiniaVuex
API 复杂度极简(无 mutations)较复杂(mutations/actions)
TypeScript原生支持需额外类型定义
模块化天然扁平化嵌套模块
包大小~1KB~4KB
Composition API原生适配需额外插件

最佳实践

  1. Store 命名:使用 useXxxStore 格式(如 useUserStore)。
  2. 状态初始化:始终用函数返回 state 避免共享状态污染。
  3. 修改状态:优先用 $patch 批量更新:
    counter.$patch({ count: counter.count + 1 });
    // 或函数形式
    counter.$patch((state) => state.items.push(newItem));
    
  4. 重置状态counter.$reset() 恢复初始值。
  5. 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