Vue Pinia 持久化存储二次封装

什么是 Pinia ?

Pinia 是2019年由vue.js官方成员重新设计的新一代状态管理库,类似Vuex。这里就不过多介绍,具体Pinia使用方法可以参考 Pinia 主页

下面我们一起研究一下基于Pinia开发的持久化存储插件

什么是持久化存储?

简单的说就是浏览器缓存与Store之间相互同步;我们在使用常规的Store存储的时候,会遇到刷新页面状态库就会被重置,这让我们很苦恼;
通常遇到这个问题,我们很容易想到用sessionStorage或者localStorage来存储相应的数据,当存储store变多时,就麻烦了,需要写一堆的废代码,不好阅读也不美观。

有没有更好的办法呢?
pinia-plugin-persist 就很好的解决的这个问题;
但在实际使用中,发现一个不方便的地方,该插件是以模块来存储的,一个store就是一模块,有时候我们需要一个一个字段去存,比如登录我们就只需要存个userInfo字段就行;为了处理类似这种情况在pinia-plugin-persist基础上进行了升级改造。

相关源码

index.d.ts

interface PersistStrategy {
  key?: string
  storage?: Storage
  paths?: string[]
}
interface PersistOptions {
  enabled: true
  strategies?: PersistStrategy[]
}
declare module 'pinia' {
  interface DefineStoreOptionsBase<S, Store> {
    persist?: PersistOptions
  }
}

export { PersistOptions, PersistStrategy }

pinia-store-persist.ts

import { PiniaPluginContext } from 'pinia'
import { PersistStrategy } from '../pinia-persist'

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

// 更新本地缓存
export const updateStorage = (strategy: PersistStrategy, store: Store) => {
  const storage = strategy?.storage || sessionStorage
  const paths = strategy?.paths || []
  if (strategy.key) {
    // 判断是否按照模块缓存
    const state = paths.reduce((obj, key) => {
      obj[key] = store.$state[key]
      return obj
    }, {} as PartialState)
    storage.setItem(strategy.key, JSON.stringify(state))
  } else {
    // 单个缓存
    paths.forEach((key) => {
      const state = store.$state[key]
      storage.setItem(key, JSON.stringify(state))
    })
  }
}

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

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

    strategies.forEach((strategy) => {
      const storage = strategy?.storage || sessionStorage
      const paths = strategy?.paths || []
      if (strategy.key) {
        const result = storage.getItem(strategy.key)
        result && store.$patch(JSON.parse(result))
      } else {
        paths.forEach((key) => {
          const result = storage.getItem(key)
          if (result) {
            const obj: { [key: string]: any } = {}
            obj[key] = JSON.parse(result)
            // 同步更新store数据
            store.$patch(obj)
          }
        })
      }
    })

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

引入

store/index.ts

import { createPinia } from 'pinia'
import piniaStorePersist from '@/plugins/pinia-persist/pinia-store-persist'

const store = createPinia().use(piniaStorePersist)

export default store

使用

export const CommonStore = defineStore('common', {
  //...
  persist: {
    enabled: true,
    strategies: [
      {
        storage: localStorage,
        paths: ['userInfo']
      }
    ]
  }
})

最后

如果本文对您有什么帮助,别忘了动动手指点个赞❤️。 本文如果有错误和不足之处,欢迎大家在评论区指出,多多提出您宝贵的意见!

原文链接:https://juejin.cn/post/7314618884451041320 作者:前端老K

(0)
上一篇 2023年12月22日 下午4:43
下一篇 2023年12月22日 下午4:53

相关推荐

发表回复

登录后才能评论