Vue3整合pinia及持久化存储

1,995 阅读2分钟

1、pinia官网:pinia.web3doc.top/introductio…

2、持久化插件pinia-plugin-persist官网:seb-l.github.io/pinia-plugi…

一、定义

Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。 Store有三个概念,stategetters 和 actions 并且可以安全地假设这些概念等同于组件中的“数据”、“计算”和“方法”。

二、使用

npm install pinia

npm install pinia-plugin-persist //持久化插件

src/stores/index.ts

import {createPinia} from 'pinia'
//pinia持久化插件
import piniaPluginPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPluginPersist)

export default store

main.ts

import { createApp } from 'vue'
import pinia from '@/stores'
const app = createApp(App)
app.use(pinia)
app.mount('#app')

src/stores/userInfo.ts

import { defineStore } from 'pinia'

export const userInfoStore = defineStore('userInfo',{
  state:()=>{
    return{
      personId:"",
      personName:""
    }
  },
  actions:{
    setPersonId(value:string){
      this.personId = value
    },
    setPersonName(value:string){
      this.personName = value
    }
  },
  //开启数据持久化缓存 默认`sessionStorage` 储存
  persist:{
    enabled:true,
    strategies:[
      {
        storage:localStorage,//存储方式
        paths:["personId","personName"]//存储属性
      }
    ]
  }
})

login.ts

import {userInfoStore} from '@/stores/userInfo'

const userStore = userInfoStore()
const doLogin = async()=>{
        const res = await api.get("/api/toLogin")
        console.log("res:",res)
        let data = res.data;
        if(data.code === 200){
            let loginConfig = data.data;
            let personId = loginConfig.person_id;
            let personName = loginConfig.person_name;
            userStore.setPersonId(personId)
            userStore.setPersonName(personName)
            router.push("/")
        }
    }

三、源码解读

type Store = PiniaPluginContext['store'];
type PartialState = Partial<Store['$state']>;

export const updateStorage = (strategy: PersistStrategy, store: Store) => {

  // 默认使用 sessionStorage
  const storage = strategy.storage || sessionStorage
  
  // 默认存储 key 为 store.$id
  const storeKey = strategy.key || store.$id

  if (strategy.paths) {
  
    // 遍历 paths 将对应的属性收集到 finalObj 中
    const partialState = strategy.paths.reduce((finalObj, key) => {
      finalObj[key] = store.$state[key]
      return finalObj
    }, {} as PartialState)
    
    // 执行存储
    storage.setItem(storeKey, JSON.stringify(partialState))
  } else {
  
    // 如果没有 paths,则按整个 store.$state 存储
    storage.setItem(storeKey, JSON.stringify(store.$state))
  }
}


export default ({ options, store }: PiniaPluginContext): void => {

  // 判断插件功能是否开启
  if (options.persist?.enabled) {
  
    // 默认策略实例
    const defaultStrat: PersistStrategy[] = [{
      key: store.$id,
      storage: sessionStorage,
    }]

    const strategies = options.persist?.strategies?.length ? options.persist?.strategies : defaultStrat

    strategies.forEach((strategy) => {
      const storage = strategy.storage || sessionStorage
      const storeKey = strategy.key || store.$id
      const storageResult = storage.getItem(storeKey)

      if (storageResult) {
      
        // 如果 storage 中存在同步数据
        store.$patch(JSON.parse(storageResult))
        updateStorage(strategy, store)
      }
    })

    store.$subscribe(() => {
    
      // 监听 state 变化,同步更新 storage
      strategies.forEach((strategy) => {
        updateStorage(strategy, store)
      })
    })
  }
}

四、pinia与vuex的区别

1、pinia没有mutation,只有state,getters,action[同步、异步]使用它来修改state数据

2、pinia没有modules配置,每一个独立的仓库都是defineStore生成出来的

五、pinia和vuex的优缺点

Pinia优点:

  • 完整的 TypeScript 支持:与在 Vuex 中添加 TypeScript 相比,添加 TypeScript 更容易
  • 极其轻巧(体积约 1KB)
  • store 的 action 被调度为常规的函数调用,而不是使用 dispatch 方法或 MapAction 辅助函数,这在 Vuex 中很常见
  • 支持多个Store
  • 支持 Vue devtools、SSR 和 webpack 代码拆分

Pinia的缺点

  • 不支持时间旅行和编辑等调试功能

Vuex的优点

  • 支持调试功能,如时间旅行和编辑
  • 适用于大型、高复杂度的Vue.js项目

Vuex的缺点

  • 从 Vue 3 开始,getter 的结果不会像计算属性那样缓存
  • Vuex 4有一些与类型安全相关的问题

何时使用Pinia,何时使用Vuex

个人感觉:,由于Pinea是轻量级的,体积很小,它适合于中小型应用。它也适用于低复杂度的Vue.js项目,因为一些调试功能,如时间旅行和编辑仍然不被支持。
将 Vuex 用于中小型 Vue.js 项目是过度的,因为它重量级的,对性能降低有很大影响。因此,Vuex 适用于大规模、高复杂度的 Vue.js 项目。