【Vue3】状态仓库持久化

前言

由于 vuexpinia 是将数据存储到内存中的,所以刷新页面后数据会丢失。如果想要持久化存储,就需要将数据同步到 WebStorage。可以使用现有的插件或者自己手写一个插件,本文对二者均有介绍。

其中手写插件案例使用两个简单模块,分别为 count++计数器 和 input输入框,演示如何持久化状态仓库。

在这里插入图片描述

vuex

1. 手写插件

自定义一个插件,用于在 组件卸载 时将 state 同步到 WebStorage

store/index.js 使用插件

import Vue from "vue"
import Vuex from "vuex"
import myPlugin from "./plugins/persistent" // 引入自定义插件
import count from "./modules/count"
import text from "./modules/text"

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    count,
    text,
  },
  plugins: [myPlugin], // 使用插件
})

./plugins/persistent.js

const myPlugin = (store) => {
  // 在 store 初始化时调用
  console.log(store)
}

export default myPlugin

查看参数 store,state为当前仓库状态

在这里插入图片描述

考虑到频繁存储对性能的浪费,只需在 beforeunload 时将仓库状态同步到 WebStorage 即可。

const KEY = "VUEX_STORE"

const myPlugin = (store) => {
  // 保存仓库数据到本地
  window.addEventListener("beforeunload", () => {
    localStorage.setItem(KEY, JSON.stringify(store.state))
  })

  // 恢复仓库数据
  try {
    const localState = localStorage.getItem(KEY)
    if (localState) store.replaceState(JSON.parse(localState))
  } catch {
    console.log("数据恢复失败")
  }
}

export default myPlugin

在这里插入图片描述

继续优化,可传入配置项用于自定义key、选择存储localStoragesessionStorage、是否立即同步本地存储

./plugins/persistent.js

const myPlugin = (options) => {
  return (store) => {
    const { key, immediately, storageType } = options
    const KEY = key || "VUEX_STORE"
    const storageMap = {
      sessionStorage: sessionStorage,
      localStorage: localStorage,
    }
    const STORAGE = storageMap[storageType] || localStorage // 默认使用 localStorage

    if (immediately) {
      // 仓库数据实时同步到本地存储
      store.subscribe((mutation, state) => {
        STORAGE.setItem(KEY, JSON.stringify(state))
      })
    } else {
      // 页面刷新时,存储仓库数据
      window.addEventListener("beforeunload", () => {
        STORAGE.setItem(KEY, JSON.stringify(store.state))
      })
    }

    // 恢复仓库数据
    try {
      const localState = STORAGE.getItem(KEY)
      if (localState) store.replaceState(JSON.parse(localState))
    } catch {
      console.log("数据恢复失败")
    }
  }
}

export default myPlugin

使用插件时,传入配置项

plugins: [
  myPlugin({
    key: "vx-store",
    storageType: window.sessionStorage,
    immediately: true,
  }),
], // 使用插件

在这里插入图片描述

2. 使用 vuex-persistedstate 插件

插件地址

下载插件

npm i vuex-persistedstate

store/index.js

// store/index.js
import Vue from "vue"
import Vuex from "vuex"
// import myPlugin from "./plugins/persistent" // 引入自定义插件
import count from "./modules/count"
import text from "./modules/text"

import createPersistedState from "vuex-persistedstate"

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    count,
    text,
  },
  plugins: [createPersistedState()], // 使用插件
})

该插件默认会在每次修改后同步到 localStorage,key 为 vuex

在这里插入图片描述

可以手动传入配置项,如使用 sessionStorage、key 为 vx_store

plugins: [
  createPersistedState({
    key: "vx_store", // 存储名称
    storage: window.sessionStorage,
  }),
], // 使用插件

在这里插入图片描述

pinia

1. 手写插件

入口文件,pinia使用插件

import { createApp } from "vue"
import "./style.css"
import App from "./App.vue"
import { createPinia } from "pinia" 
import myPlugin from "@/store/plugins/persistent.js" 

const pinia = createPinia() 
pinia.use(myPlugin) // 使用插件

const app = createApp(App)
app.use(pinia) 

plugins/persistent.js

export default function (context) {
  console.log(context)
}

查看打印,不同于 vuex,pinia 将每个使用的模块分别打印,需要对每一个模块进行处理

在这里插入图片描述

与 vuex 一样,默认只有在页面销毁时同步到本地存储

const KEY_PREFIX = "PINIA-STORE-"

export default function (context) {
  const { store } = context
  const KEY = KEY_PREFIX + store.$id

  // 存
  window.addEventListener("beforeunload", () => {
    localStorage.setItem(KEY, JSON.stringify(store.$state))
  })
  // 取
  try {
    const localState = localStorage.getItem(KEY)
    if (localState) {
      store.$patch(JSON.parse(localState))
    }
  } catch {
    console.log("读取失败")
  }
}

在这里插入图片描述

继续优化,可传入配置项包括自定义key前缀、选择存储localStoragesessionStorage、是否立即同步本地存储

const KEY_PREFIX = "PINIA-STORE-"

export default function createPiniaPlugin(options = {}) {
  // 解构传入的参数
  const {
    keyPrefix = KEY_PREFIX,
    storageType = "localStorage",
    immediately,
  } = options
  const storageMap = {
    localStorage: localStorage,
    sessionStorage: sessionStorage,
  }
  const STORAGE = storageMap[storageType]

  // 返回实际的插件函数
  return (context) => {
    const { store } = context
    const KEY = keyPrefix + store.$id

    if (immediately) {
      // 仓库数据实时同步到本地存储
      store.$subscribe((mutation, state) => {
        STORAGE.setItem(KEY, JSON.stringify(state))
      })
    } else {
      // 页面刷新时,存储仓库数据
      window.addEventListener("beforeunload", () => {
        STORAGE.setItem(KEY, JSON.stringify(store.$state))
      })
    }

    // 取出数据
    try {
      const localState = STORAGE.getItem(KEY)
      if (localState) {
        store.$patch(JSON.parse(localState))
      }
    } catch {
      console.log("读取失败")
    }
  }
}
pinia.use(
  myPlugin({
    keyPrefix: "MY-STORE-", // 自定义的前缀
    storageType: "sessionStorage", // 使用 sessionStorage
    immediately: true,
  })
) // 使用本地持久化插件

在这里插入图片描述

2. 使用 pinia-plugin-persistedstate 插件

官方地址

下载插件

npm i pinia-plugin-persistedstate

使用插件

import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' //引入持久化插件

pinia.use(piniaPluginPersistedstate)

创建 Store 时,将 persist 选项设置为 true,整个 Store 将使用默认持久化配置保存。

默认配置:

  • 使用 localStorage 存储
  • key 为 store.$id
  • 存储整个 state
import { defineStore } from "pinia"

export const useCountStore = defineStore("count", {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++
    },
  },
  persist: true, // 默认配置
})

只对 count 这个仓库做了持久化处理,input输入框对应的 text 仓库并没有持久化

在这里插入图片描述

自定义配置项

  • key:自定义key
  • storage:存储方式
  • pick:选择存入哪些字段
import { defineStore } from "pinia"

export const useCountStore = defineStore("count", {
  state: () => ({
    count: 0,
    name: "田本初",
  }),
  actions: {
    increment() {
      this.count++
    },
  },
  persist: {
    key: "PINIA-CountStore",
    storage: sessionStorage, // 存储方式
    pick: ["count"], //指定 state 中哪些数据需要被持久化。[] 表示不持久化任何状态,undefined 或 null 表示持久化整个 state
  },
})

可以发现只有count仓库采用持久化、key为自定义、采用 sessionStorage 存储并且只存入了count

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

田本初

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值