在 Vue3 的生态体系中,Pinia 作为 Vue 官方推荐的状态管理库,已经逐渐取代 Vuex 成为主流选择。相比 Vuex,Pinia 语法更简洁、类型推导更友好、开发体验更流畅。

在入门阶段,我们已经知道 Pinia 的核心概念:State、Getters、Actions。但在实际项目中,光靠这些基础功能往往不够。复杂应用需要 模块化拆分、跨 Store 数据交互,以及持久化存储 等高级能力。

本文将带你深入 Pinia 的高级用法,结合实际场景,逐一解析 模块化存储、跨 Store 通信与持久化方案


一、为什么需要高级用法?

随着项目规模的增长,状态管理会遇到以下挑战:

  1. 模块划分:业务逻辑多,状态难以集中管理,需要拆分成独立模块。

  2. 跨模块依赖:一个模块可能依赖另一个模块的数据或方法。

  3. 数据持久化:页面刷新或重新打开时,状态会丢失,需要本地化存储。

Pinia 在设计上提供了灵活的 API,完全可以优雅地解决这些问题。


二、模块化存储(Store 模块拆分)

在一个大型项目中,把所有状态都放在一个 Store 里会导致文件臃肿、难以维护。Pinia 推荐 一个功能对应一个 Store,实现模块化管理。

1. 创建模块化 Store

例如我们有 用户模块 和 购物车模块

收起代码语言:TypeScript

AI代码解释

// stores/user.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    id: null as number | null,
    name: '' as string,
    token: '' as string,
  }),
  actions: {
    setUser(id: number, name: string, token: string) {
      this.id = id
      this.name = name
      this.token = token
    },
  },
})

// stores/cart.ts
import { defineStore } from 'pinia'

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [] as { id: number; name: string; price: number }[],
  }),
  actions: {
    addItem(item: { id: number; name: string; price: number }) {
      this.items.push(item)
    },
    clearCart() {
      this.items = []
    },
  },
})

2. 在组件中使用

代码语言:HTML

AI代码解释

<script setup lang="ts">
import { useUserStore } from '@/stores/user'
import { useCartStore } from '@/stores/cart'

const userStore = useUserStore()
const cartStore = useCartStore()

userStore.setUser(1, '张三', 'abc123')
cartStore.addItem({ id: 101, name: 'MacBook', price: 9999 })
</script>

通过拆分模块,逻辑更清晰,文件更易维护。


三、跨 Store 通信

在实际业务中,模块之间不可避免地存在依赖。例如:购物车结算时需要验证用户是否已登录。这时就涉及到跨 Store 调用。

1. 在 Action 中访问其他 Store

Pinia 允许在一个 Store 内引入另一个 Store,并直接调用:

收起代码语言:TypeScript

AI代码解释

// stores/cart.ts
import { defineStore } from 'pinia'
import { useUserStore } from './user'

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [] as { id: number; name: string; price: number }[],
  }),
  actions: {
    checkout() {
      const userStore = useUserStore()
      if (!userStore.token) {
        throw new Error('请先登录后再结算!')
      }
      console.log('订单已提交', this.items)
      this.items = []
    },
  },
})

2. 在组件中同时使用多个 Store

收起代码语言:HTML

AI代码解释

<script setup lang="ts">
import { useUserStore } from '@/stores/user'
import { useCartStore } from '@/stores/cart'

const userStore = useUserStore()
const cartStore = useCartStore()

function handleCheckout() {
  try {
    cartStore.checkout()
    alert('结算成功!')
  } catch (err) {
    alert((err as Error).message)
  }
}
</script>

这种方式使模块间可以相互调用,保持业务解耦。


四、持久化存储方案

默认情况下,Pinia 的状态存储在内存中,刷新页面会丢失。对于用户信息、购物车数据等,需要实现 持久化存储

1. 使用插件实现持久化

Pinia 官方并未内置持久化功能,但可以借助社区插件 pinia-plugin-persistedstate

安装:

代码语言:Bash

AI代码解释

npm install pinia-plugin-persistedstate

配置:

代码语言:TypeScript

AI代码解释

// main.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

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

app.use(pinia)

2. 在 Store 中启用持久化

代码语言:TypeScript

AI代码解释

// stores/user.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    id: null as number | null,
    name: '',
    token: '',
  }),
  persist: true, // 开启持久化
})

3. 自定义持久化配置

代码语言:TypeScript

AI代码解释

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [] as { id: number; name: string; price: number }[],
  }),
  persist: {
    key: 'my-cart',
    storage: sessionStorage, // 存储到 sessionStorage
    paths: ['items'], // 只持久化 items 字段
  },
})

这样就能在刷新或重新进入页面时恢复数据,大大提升用户体验。


五、总结与最佳实践

通过本文的讲解,我们深入了解了 Pinia 的高级用法:

  1. 模块化存储:将不同功能拆分成独立 Store,提升可维护性。

  2. 跨 Store 通信:支持在 Action 中引入并调用其他 Store,实现模块之间的协作。

  3. 持久化方案:借助插件 pinia-plugin-persistedstate,让状态在页面刷新后依然保持。

👉 最佳实践建议:

  • 模块化设计:每个业务功能一个 Store,避免过于集中。

  • 跨 Store 依赖要适度:过度耦合会导致维护困难,必要时可考虑事件总线或全局状态。

  • 持久化只存关键数据:避免存储体积过大或敏感信息(如明文密码)。

Pinia 不仅简洁优雅,还能轻松应对复杂项目场景。掌握这些高级用法,将帮助你在 Vue3 项目中更加游刃有余。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐