Vue Pinia 插件详解

Pinia 是 Vue.js 官方推荐的状态管理库(自 Vue 3 起),用于替代 Vuex。它具有更简洁的 API、更好的 TypeScript 支持、模块化设计以及对 Composition API 的天然适配。

一、Pinia 简介

  • 作者:Eduardo San Martin Morote(Vue 团队核心成员)
  • 特点
    • 无 mutations,只有 state、getters、actions
    • 支持 Vue 2(≥2.6.14)和 Vue 3
    • 完美支持 TypeScript(无需额外配置)
    • 支持 Vue Devtools 调试
    • 支持服务端渲染(SSR)
    • 模块自动注册,无需手动嵌套
    • 轻量(gzip 后约 1KB)

二、安装与基本使用

  1. 安装
bash 复制代码
# Vue 3 项目
npm install pinia

# Vue 2 项目(需额外安装 composition-api)
npm install pinia @vue/composition-api
  1. 在 Vue 应用中注册
javascript 复制代码
// main.js (Vue 3)
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)
app.mount('#app')
注意:Vue 2 中使用 new Vue({ pinia }) 语法。 

三、定义 Store

使用 defineStore 创建 store,接受两个参数:id 和 配置对象(或函数)。

  1. 选项式写法(类似 Vuex)
javascript 复制代码
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    name: 'Eduardo'
  }),

  getters: {
    doubleCount: (state) => state.count * 2,
    // 带参数的 getter(使用箭头函数返回函数)
    doubleCountPlus: (state) => (n) => state.count * 2 + n
  },

  actions: {
    increment() {
      this.count++
    },
    reset() {
      this.count = 0
    },
    // 支持异步
    async fetchData() {
      const res = await fetch('/api/data')
      this.data = await res.json()
    }
  }
})
  1. 函数式写法(使用 Composition API)
javascript 复制代码
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Eduardo')

  const doubleCount = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  function reset() {
    count.value = 0
  }

  return { count, name, doubleCount, increment, reset }
})

✅ 推荐函数式写法:更灵活、复用性强、便于单元测试。

四、在组件中使用 Store

javascript 复制代码
<template>
  <div>
    <p>Count: {{ counter.count }}</p>
    <p>Double: {{ counter.doubleCount }}</p>
    <button @click="counter.increment">+</button>
    <button @click="reset">Reset</button>
  </div>
</template>

<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()

// 解构会丢失响应性!应使用 toRefs 或 storeToRefs
// ❌ 错误写法:
// const { count, increment } = counter

// ✅ 正确写法(推荐):
import { storeToRefs } from 'pinia'
const { count, doubleCount } = storeToRefs(counter)
const { increment } = counter
</script>

五、核心特性详解

  1. 自动响应性

State 是响应式的,修改会自动触发视图更新。

Getters 是缓存的 computed 属性。

  1. Actions

替代 mutations + actions。

可同步/异步。

可调用其他 store 的 actions。

javascript 复制代码
// 调用其他 store
const useUserStore = defineStore('user', {
  actions: {
    async login() {
      const counter = useCounterStore()
      counter.increment()
    }
  }
})
  1. Store 间通信

直接 import 并调用其他 store。

无命名空间冲突(每个 store 有唯一 ID)。

  1. TypeScript 支持

开箱即用,无需额外配置。

类型推导精准。

javascript 复制代码
interface User {
  id: number
  name: string
}

export const useUserStore = defineStore('user', () => {
  const users = ref<User[]>([])
  // 类型自动推导 ✅
})

六、插件系统(Plugin)

Pinia 支持插件扩展功能(类似 Vuex 的插件)。

示例:添加 localStorage 持久化

javascript 复制代码
// plugins/persist.js
export const persistPlugin = ({ store }) => {
  const key = `pinia:${store.$id}`
  
  // 初始化时从 localStorage 读取
  const saved = localStorage.getItem(key)
  if (saved) {
    store.$state = JSON.parse(saved)
  }

  // 监听状态变化并保存
  store.$subscribe((mutation, state) => {
    localStorage.setItem(key, JSON.stringify(state))
  })
}

// main.js
import { createPinia } from 'pinia'
import { persistPlugin } from './plugins/persist'

const pinia = createPinia()
pinia.use(persistPlugin)

插件可扩展内容:

添加属性到 store(如 $db)

修改 $state

添加新选项(如 $reset)

七、服务端渲染(SSR)支持

Pinia 原生支持 SSR,只需在服务端创建新的 Pinia 实例:

javascript 复制代码
// server-entry.js
import { createPinia } from 'pinia'

export function createApp() {
  const app = createApp(App)
  const pinia = createPinia()
  app.use(pinia)
  return { app, pinia }
}

自动处理 hydration,无需额外配置。

八、Devtools 调试

  • 自动集成 Vue Devtools。
  • 可追踪 actions 调用、状态变化。
  • 时间旅行调试(time-travel debugging)。

九、与 Vuex 对比

API 简洁性 ✅ 更简洁(无 mutations) ❌ 较复杂
TypeScript ✅ 原生支持 ⚠️ 需额外配置
模块嵌套 ✅ 扁平化(自动注册) ❌ 需手动嵌套
Composition API ✅ 天然支持 ❌ 需额外适配
包体积 ✅ 更小 ❌ 较大
Vue 2 支持 ✅(需插件)

十、最佳实践

  1. 每个 store 单文件stores/user.jsstores/product.js
  2. 使用函数式定义:便于逻辑复用和测试
  3. 避免直接修改 state:始终通过 actions
  4. 使用 storeToRefs 解构:保持响应性
  5. 合理拆分 store:按业务域划分,不要一个 store 管所有状态
相关推荐
yinuo5 分钟前
IndexedDB 使用指南
前端
小徐_233323 分钟前
2025,AI 编程元年,我用 TRAE 做了这些!
前端·程序员·trae
沛沛老爹31 分钟前
Web开发者实战RAG评估:从指标到工程化验证体系
前端·人工智能·llm·agent·rag·评估
软件技术NINI1 小时前
JavaScript性能优化实战指南
前端·css·学习·html
前端小配角1 小时前
React难上手原因找到了,原来是因为坑太多了。。。
前端
是你的小橘呀1 小时前
零基础也能懂!React Hooks实战手册:useState/useEffect上手就会,告别类组件
前端·架构
xhxxx1 小时前
从样式到结构:TailwindCss + Fragment 如何让 React 代码更干净、更高效
前端·css·react.js
Maxkim1 小时前
「✍️JS原子笔记 」深入理解JS数据类型检测的4种核心方式
前端·javascript·面试
小高0071 小时前
Elips-Core:轻量级 Node.js Web 框架核心实现
前端·javascript·node.js
Focus_1 小时前
SSE+broadcastChannel
前端