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 管所有状态
相关推荐
吃饺子不吃馅2 小时前
面试官:JWT、Cookie、Session、Token有什么区别?
前端·设计模式·面试
IT_陈寒2 小时前
React 19新特性实战:5个提升开发效率的技巧与避坑指南
前端·人工智能·后端
丙寅2 小时前
微信小程序反编译遇到 TypeError: _typeof3 is not a function
开发语言·javascript·ecmascript
青衫码上行2 小时前
【Java Web学习 | 第十篇】JavaScript(4) 对象
java·开发语言·前端·javascript·学习
CodeLongBear2 小时前
第一次搭建个人主页+GitHub部署全记录:HTML/CSS/JS前端实现+留言板踩坑
前端·个人页面·部署上线
by__csdn2 小时前
Node各版本的区别,如何选择版本以及与NPM版本对照关系
前端·npm·node.js
q***42822 小时前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
Dontla3 小时前
React zustand todos案例(带本地存储localStorage、persist)todoStore.ts
前端·react.js·前端框架
阿珊和她的猫3 小时前
WebRTC 技术深度解析:实时通信的未来引擎
前端·webpack·node.js·webrtc