Pinia状态管理实战:Store模块化设计与持久化插件配置

Pinia与Vuex的核心差异与迁移思路

Pinia是Vue3官方推荐的状态管理库,由Vue核心团队成员Eduardo San Martin Morote开发。相比Vuex 4,Pinia移除了mutations概念,API设计更贴合Composition API风格,TypeScript类型推导更完善。在Vue3生态中,Pinia已成为新项目的默认状态管理方案。

Vuex的state、getters、mutations、actions四层结构在实际使用中显得冗余。Pinia简化为state、getters、actions三层,mutations被合并进actions,无论同步还是异步操作都通过actions处理。类型支持方面,Pinia不需要额外的类型定义文件就能获得完整的IDE智能提示。

Store定义与组合式API写法

Pinia提供两种Store定义风格:Options Store和Setup Store。Setup Store使用Composition API语法,灵活性更高:

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  const items = ref([])
  const couponCode = ref('')

  const totalCount = computed(() => items.value.length)
  const totalPrice = computed(() =>
    items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
  )
  const discountPrice = computed(() => {
    if (couponCode.value === 'SAVE10') {
      return totalPrice.value * 0.9
    }
    return totalPrice.value
  })

  function addItem(product) {
    const existing = items.value.find(i => i.id === product.id)
    if (existing) {
      existing.quantity++
    } else {
      items.value.push({ ...product, quantity: 1 })
    }
  }

  function removeItem(id) {
    const index = items.value.findIndex(i => i.id === id)
    if (index > -1) items.value.splice(index, 1)
  }

  async function applyCoupon(code) {
    const res = await fetch(`/api/coupon/validate?code=${code}`)
    if (res.ok) {
      couponCode.value = code
      return true
    }
    return false
  }

  return { items, couponCode, totalCount, totalPrice, discountPrice, addItem, removeItem, applyCoupon }
})

在组件中使用Store时,通过storeToRefs解构state和getters保持响应性,actions可以直接解构:

import { useCartStore } from '@/stores/cart'
import { storeToRefs } from 'pinia'

const cartStore = useCartStore()

const { items, totalCount, totalPrice, discountPrice } = storeToRefs(cartStore)
const { addItem, removeItem, applyCoupon } = cartStore

直接从Store解构state和getters会丢失响应性,因为Pinia底层基于Vue的reactive/ref实现。storeToRefs返回的ref对象在模板中自动解包,使用方式与原始值一致。

模块化Store拆分与跨Store引用

大型前端工程化项目中,按业务域拆分Store是必要的。Pinia的Store之间可以相互引用,在action中调用其他Store的方法:

// stores/user.js
export const useUserStore = defineStore('user', () => {
  const token = ref('')
  const profile = ref(null)

  async function login(credentials) {
    const res = await api.post('/auth/login', credentials)
    token.value = res.token
    profile.value = res.profile
  }

  function logout() {
    token.value = ''
    profile.value = null
  }

  return { token, profile, login, logout }
})

// stores/order.js
export const useOrderStore = defineStore('order', () => {
  const orders = ref([])

  async function fetchOrders() {
    const userStore = useUserStore()
    const res = await api.get('/orders', {
      headers: { Authorization: `Bearer ${userStore.token}` }
    })
    orders.value = res.data
  }

  return { orders, fetchOrders }
})

跨Store引用时,useUserStore()必须在action函数内部调用,不能在Store定义的顶层调用,否则可能因为Store初始化顺序导致循环依赖问题。

pinia-plugin-persistedstate持久化配置

状态持久化是前端应用的常见需求,pinia-plugin-persistedstate插件自动将Store状态同步到localStorage或sessionStorage:

import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

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

export const useCartStore = defineStore('cart', () => {
  // ...store定义
}, {
  persist: {
    key: 'shopping-cart',
    storage: localStorage,
    paths: ['items', 'couponCode'],
  }
})

paths选项控制持久化的粒度,敏感信息如token不应存储在localStorage中。在SSR场景下,持久化配置需要区分服务端和客户端环境,避免在服务端访问localStorage报错。

Pinia在SSR中的状态Hydration

Nuxt 3内置Pinia支持,服务端渲染时自动将Store状态序列化到页面HTML中,客户端激活时通过hydrate还原状态:

// Nuxt 3中使用Pinia
export default definePageComponent({
  async setup() {
    const userStore = useUserStore()

    if (process.server) {
      await userStore.fetchProfile()
    }

    return { userStore }
  }
})

// 手动hydrate(非Nuxt环境)
if (typeof window !== 'undefined' && window.__pinia) {
  pinia.state.value = JSON.parse(window.__pinia)
}

SSR场景下,服务端在渲染前预填充Store数据,客户端激活时直接使用服务端传递的状态,避免重复请求。这要求Store的初始状态在服务端和客户端保持一致,否则会出现hydration mismatch警告。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/pinia-zhuang-tai-guan-li-shi-zhan-store-mo-kuai-hua-she-ji/

(0)
小编小编
上一篇 14小时前
下一篇 14小时前

相关推荐