手写Pinia存储的数据持久化插件

Pinia和Vuex的通病

Pinia和vuex的通病就是,页面刷新会导致数据丢失

解决通病

一、新建store

import { defineStore } from 'pinia'
//单独存放Store的名字  $id
import { Names } from './store-name'

type User = {
  name: string
  age: number
}
let res: User = {
  name: '孙悟空',
  age: 999,
}
const Login = (): Promise<User> => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        name: '孙悟空',
        age: 999,
      })
    }, 2000)
  })
}

export const useTestStore = defineStore(Names.TEST, {
  state: () => {
    return {
      user: <User>{},
      name: '飞机',
    }
  },
  //类似computed 修饰一些值
  getters: {
    newName():string {
      return `new--${this.name}-${this.getUserAge}`
    },
    getUserAge():number {
      return this.user.age
    }
  },
  // 类似methods 可以同步  异步  提交state
  actions: {
    setName() {
      this.name = '孙悟空'
    },
    async setUser() {
      this.user = await Login()
      this.setName()
    },
  },
})


//base

export const  useBaseStore = defineStore(Names.BASE, {
  state: () => {
    return {
      baseCurrent:1
    }
  }
})

存放store名字的文件
store-names.ts

//存放store的名字

export const  enum Names {
  TEST = 'TEST',
  BASE = 'BASE'
}

二、在main.ts中引入并使用手写的插件

main.ts

import { createApp, toRaw } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './assets/main.css'
import piniaToLocalStoragePlugin from './stores/piniaToLocalStoragePlugin'

const app = createApp(App)
const store = createPinia()
store.use(
  piniaToLocalStoragePlugin({
    key: 'pinia', // 这是给缓存到本地时,加一个特殊的前缀,以免造成污染到其他缓存数据
    needKeepIds: ['BASE','TEST'], // 对于特定store进行持久化,store的名字都在store-names文件中抽离出来了,空或者不传,则对所有的store进行缓存到本地
  })
)

app.use(router)
app.use(store)
app.mount('#app')

三、手写的持久化插件

这个就是本文的主角了
piniaToLocalStoragePlugin.ts

import type { PiniaPluginContext } from 'pinia'
import { toRaw } from 'vue'

type Options = {
  key: string
  needKeepIds?: string[]
}

// 来个持久化存储的函数
const setStorage = (key: string, value: any) => {
  localStorage.setItem(key, JSON.stringify(value))
}
// 来个取的函数
const getStorage = (key: string) => {
  return localStorage.getItem(key)
    ? JSON.parse(localStorage.getItem(key) as string)
    : {}
}

const __piniaKey__: string = 'piniaKey'

const piniaToLocalStoragePlugin = (options: Options) => {
  const { key, needKeepIds = [] } = options
  //使用函数柯里化
  return (context: PiniaPluginContext) => {

    const { store } = context
    if (needKeepIds.length === 0) {
      //没有指定存全部
      // 有个监听是$subscribe  1. 先监听是否改变了store的内容 改变了就存
      store.$subscribe(() => {
        console.log(' change' )
        //无论哪个 state  所有的改变都走这个函数  所以我们可以在这里搞一些动作
        setStorage(`${key ?? __piniaKey__}-${store.$id}`, toRaw(store.$state))
      })
    } else {
      //有指定要存哪些
      //使用短路运算
      needKeepIds.includes(store.$id) &&
        store.$subscribe(() => {
          setStorage(`${key ?? __piniaKey__}-${store.$id}`, toRaw(store.$state))
        })
    }

    //2. 获取本地存储的localStorage 有就放在页面上
    const data = getStorage(`${key ?? __piniaKey__}-${store.$id}`)
    // console.log('data', data) //取到data了 怎么送给store呢
    return {
      ...data,
    }
  }
}

export default piniaToLocalStoragePlugin

posted @ 2022-09-15 15:04  bbigger004  阅读(587)  评论(0编辑  收藏  举报