自学内容网 自学内容网

Pinia 是 Vue 的专属状态管理库

Pinia 是 Vue 的专属状态管理库,它被称为“下一代 Vuex”。相比于 Vuex,Pinia 在 Vue 3 中更简单、更轻量,且对 TypeScript 支持极好,完全摒弃了 Vuex 中繁琐的 mutations
以下是 Pinia 在 Vue 3 中的完整使用流程,包含 定义 store在组件中使用 以及 State、Getter、Action 的详细操作

1. 安装与挂载

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

npm install pinia
# 或
yarn add pinia

挂载:

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

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
<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。

<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
    // ✅ 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

// 安装后配置
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 总结

特性VuexPinia
修改数据必须通过 mutations (同步) 和 actions (异步)移除 mutations,直接修改或统一用 actions
TypeScript支持较弱,需要大量类型声明原生支持,类型推断完美
模块化需要创建 modules,嵌套复杂每个 Store 独立,天然模块化,无嵌套
体积较大极轻量 (约 1KB)
一句话总结:在 Vue 3 中,Pinia 几乎是状态管理的唯一首选,它比 Vuex 更简单、更强大。

原文地址:https://blog.csdn.net/liming1016/article/details/159920341

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!