Pinia 是 Vue 的专属状态管理库

Pinia 是 Vue 的专属状态管理库,它被称为"下一代 Vuex"。相比于 Vuex,Pinia 在 Vue 3 中更简单、更轻量,且对 TypeScript 支持极好,完全摒弃了 Vuex 中繁琐的 mutations

以下是 Pinia 在 Vue 3 中的完整使用流程,包含 定义 store在组件中使用 以及 State、Getter、Action 的详细操作

1. 安装与挂载

首先需要在项目中安装 Pinia,并在 main.js 中挂载。
安装:

bash 复制代码
npm install pinia
# 或
yarn add pinia

挂载:

javascript 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia' // 引入 createPinia
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia) // 挂载到 Vue 应用
app.mount('#app')

2. 定义 Store

推荐在 src/stores 目录下创建文件(如 user.jsuser.ts)。Pinia 使用 defineStore 定义 Store,它接收两个参数:唯一 ID配置对象

配置对象支持两种写法:Options API 风格 (类似 Vuex)和 Setup API 风格 (推荐,更符合 Vue 3 习惯)。
示例文件:src/stores/user.js

javascript 复制代码
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// 写法一:Setup Store (推荐 ⭐)
// 类似于 Vue 3 的 setup() 函数,ref 就是 state,computed 就是 getter,function 就是 action
export const useUserStore = defineStore('user', () => {
  // ---------- State ----------
  const count = ref(0)
  const userName = ref('张三')
  const userList = ref([])
  // ---------- Getter ----------
  // 类似于计算属性
  const doubleCount = computed(() => count.value * 2)
  // ---------- Action ----------
  // 异步操作或同步逻辑都在这里,不再区分 mutations 和 actions
  function increment() {
    count.value++
  }
  
  async function fetchUserList() {
    // 模拟异步请求
    const res = await new Promise(resolve => {
      setTimeout(() => resolve(['李四', '王五']), 1000)
    })
    userList.value = res
  }
  // 必须返回所有你想暴露的属性和方法
  return { count, userName, userList, doubleCount, increment, fetchUserList }
})

3. 在组件中使用

在组件中导入定义好的 Store 函数并执行,即可获取 Store 实例。

场景 A:读取与展示 State/Getter
html 复制代码
<template>
  <div>
    <p>用户名:{{ userStore.userName }}</p>
    <p>双倍计数:{{ userStore.doubleCount }}</p>
    
    <!-- 推荐使用 storeToRefs 解构,保持响应式 -->
    <p>解构后的计数:{{ count }}</p>
  </div>
</template>
<script setup>
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia' // 官方提供的解构工具
const userStore = useUserStore()
// ⚠️ 注意:直接解构 userStore 会丢失响应式!
// const { userName } = userStore // ❌ 错误:userName 不再是响应式的
// ✅ 正确:使用 storeToRefs 解构 State 和 Getter
const { userName, count, doubleCount } = storeToRefs(userStore)
</script>
场景 B:修改 State 与调用 Action

修改数据非常灵活,可以直接赋值,也可以调用 Action。

html 复制代码
<template>
  <button @click="handleChange">修改数据</button>
  <button @click="handleAction">调用方法</button>
  <button @click="resetStore">重置状态</button>
</template>
<script setup>
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
const handleChange = () => {
  // 方式 1:直接修改 (Pinia 允许直接修改,不像 Vuex 需要 mutations)
  userStore.count = 10
  
  // 方式 2:$patch 批量修改 (性能更好)
  userStore.$patch({
    count: 20,
    userName: '李四'
  })
  
  // 方式 3:$patch 函数式修改 (适合复杂逻辑)
  userStore.$patch((state) => {
    state.count++
    state.userName = state.userName + '1'
  })
}
const handleAction = () => {
  // 调用 Store 中的 Action
  userStore.increment()
  userStore.fetchUserList()
}
const resetStore = () => {
  // 方式 4:重置 State 到初始状态
  userStore.$reset()
}
</script>

4. 进阶技巧

1. 解构陷阱与 storeToRefs

这是新手最容易踩的坑。

  • State/Getter :如果直接解构(const { count } = store),数据会失去响应式。必须使用 storeToRefs

  • Action :方法可以直接解构,不需要 storeToRefs

    javascript 复制代码
    // ✅ Action 直接解构完全没问题
    const { increment, fetchUserList } = userStore 
2. 修改 State 的三种方式对比
方式 代码示例 适用场景
直接赋值 store.count++ 简单、逻辑少的修改
$patch (对象) store.$patch({ count: 1, name: 'a' }) 同时修改多个属性,性能稍好
$patch (函数) store.$patch(s => s.count++) 适合修改逻辑比较复杂的情况
3. 持久化存储

Pinia 默认数据存放在内存中,刷新页面会丢失。如需持久化(如存入 localStorage),通常搭配插件 pinia-plugin-persistedstate

javascript 复制代码
// 安装后配置
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
// 在 defineStore 中开启
defineStore('user', () => { ... }, {
  persist: true // 开启持久化
})

5. Pinia vs Vuex 总结

特性 Vuex Pinia
修改数据 必须通过 mutations (同步) 和 actions (异步) 移除 mutations,直接修改或统一用 actions
TypeScript 支持较弱,需要大量类型声明 原生支持,类型推断完美
模块化 需要创建 modules,嵌套复杂 每个 Store 独立,天然模块化,无嵌套
体积 较大 极轻量 (约 1KB)
一句话总结:在 Vue 3 中,Pinia 几乎是状态管理的唯一首选,它比 Vuex 更简单、更强大。
相关推荐
用户69371750013842 小时前
Android 开发,别只钻技术一亩三分地,也该学点“广度”了
android·前端·后端
郑鱼咚2 小时前
别再神化Spec了,它可能只是AI Coding的临时补丁
前端
张元清2 小时前
React 鼠标追踪与交互效果实战
前端·javascript·面试
MinterFusion2 小时前
HTML DOM元素的定位问题
前端·css·html
落魄江湖行2 小时前
入门篇六 Nuxt4错误处理:给应用装个安全气囊
前端·typescript·nuxt4
薛定猫AI2 小时前
【技术干货】用 design.md 驯服 AI 生成前端:从 Awesome Design 到工程化落地实践
前端·人工智能
kyriewen2 小时前
你的JS代码总在半夜崩溃?TypeScript来“上保险”了
前端·javascript·typescript
iReachers3 小时前
HTML打包EXE配置管理教程:多项目打包设置一键保存、加载与切换
java·前端·javascript
武藤一雄3 小时前
WPF中ViewModel之间的5种通讯方式
开发语言·前端·microsoft·c#·wpf