仓库持久化——以vue3为例

201 阅读4分钟

在开发的过程当中我们会遇到仓库持久化的问题,今天给大家分享一下仓库持久化的基本用法和原理,状态管理库有两种一种是Vuex,一种是Pinia,两种都分享一下。

仓库持久化有专门的插件可以使用,此篇文章没有采用插件,而是用了自定义的函数插件来实现的供大家参考

此文章以vue3为例,UI组件用的是Naive UI

Vuex

创建vuex仓库

下载并配置vuex

//这里的 @next 是为了安装 Vuex 4,它适用于 Vue 3。
pnpm add vuex@next

配置Vuex仓库

下载完成后配置仓库,在main.ts引入vuex

//main.ts

import { createApp } from 'vue'
import vuex from './storeVuex/index'

const app = createApp(App)
app.use(vuex).mount('#app')

在src下创建文件夹 storeVuex,以及存放模块的modules文件夹和一些ts文件,这是Vuex仓库的目录结构

image.png

小仓库  user.ts

//user.ts

const user = {
  namespaced: true,
  state: {
    name: '周杰伦',
    age: 35,
    role: '歌手',
  },
  mutations: {
    setName(state, newName) {
      state.name = newName
    },
    setAge(state, newAge) {
      state.age = newAge
    },
    setRole(state, newRole) {
      state.role = newRole
    },
  },
  actions: {
    updateName({ commit }, newName) {
      commit('setName', newName)
    },
    updateAge({ commit }, newAge) {
      commit('setAge', newAge)
    },
    //修改State中的值
    update({ commit }, payload) {
      commit('setName', payload.name)
      commit('setAge', payload.age)
      commit('setRole', payload.role)
    },
  },
}
export default user

在大仓库中引入小仓库  index.ts

//index.ts

import { createStore } from 'vuex'
import user from './modules/user'
//这里引入我们自定义的插件,其实就是一个函数
import myPlugin from './myPlugin.ts'
const store: any = createStore({
  modules: {
    test: user,
  },
  //plugin的执行时机是在仓库初始化完成之后调用
  plugins: [myPlugin],
})
export default store

编写插件函数

自定义插件  myPlugin.ts

编写我们的插件函数。

//myPlugin.ts

const myPlugin = (store) => {
  //store 是仓库对象

  //存储数据
  //beforeunload事件——用户正在离开
  window.addEventListener('beforeunload', (e) => {
    localStorage.setItem('USER', JSON.stringify(store.state))
  })
  // 取数据
  const user = localStorage.getItem('USER')
  if (user) {
    store.replaceState(JSON.parse(user))
  }
}
export default myPlugin

使用仓库

在页面中使用store

<template>
  <div>
    <div class="store-container">
      <h2>vuex</h2>
      <n-form
        ref="formRef"
        inline
        label-width="auto"
        label-placement="left"
        :model="formJay"
        :size="size"
      >
        <n-form-item label="姓名" path="name">
          <n-input v-model:value="formJay.name" placeholder="输入姓名" />
        </n-form-item>
        <n-form-item label="年龄" path="age">
          <n-input v-model:value="formJay.age" placeholder="输入年龄" />
        </n-form-item>
        <n-form-item label="角色" path="role">
          <n-input v-model:value="formJay.role" placeholder="角色" />
        </n-form-item>
        <n-form-item>
          <n-button type="primary" attr-type="button" @click="updateJay">
            提交
          </n-button>
        </n-form-item>
      </n-form>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { useStore } from 'vuex'
import { onMounted, ref } from 'vue'

const userStore = useStore()
const formRef = ref<any>()

const size = ref<'small' | 'medium' | 'large'>('medium')
//取值
const formJay = ref<any>({
  name: undefined,
  age: undefined,
  role: undefined,
})
const updateJay = () => {
//更新数据
  userStore.dispatch('user/update', formJay.value)
}
onMounted(() => {
//取值 赋值
  formJay.value = userStore.state.user
})
</script>
<style lang="scss" scoped>
.store-container {
  width: 100%;
  height: 400px;
  //text-align: center;
  margin-top: 100px;
  h2 {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    margin-bottom: 20px;
  }
}
</style>

查看状态

修改完数据之后——点击提交,然后刷新页面,数据不会丢失,说明仓库状态持久化成功了

我们是将数据存储在了 localStorage,所以要在localstorage中查看数据是否保存成功,USER是在插件函数中 监听beforeunload 存的值

222.png

Pinia

创建Pinia仓库

pnpm add pinia

配置Pinia仓库

myPlugin是自己编写的插件函数

//main.ts

import { createApp } from 'vue'
import pinia from './store'
//pinia使用自定义插件
import piniaPlugin from './store/myPlugin'
pinia.use(piniaPlugin)
const app = createApp(App)
app.use(pinia).mount('#app')

在src下创建文件夹 store,以及存放模块的modules文件夹和一些ts文件,这是Pinia仓库的目录结构

image.png

创建小仓库 user.ts

//user.ts
import { defineStore } from 'pinia'
const useUserStore = defineStore('User', {
  state: () => ({
    name: '林俊杰',
    age: 35,
    role: '歌手',
  }),
  actions: {
    updateName(newName) {
      this.name = newName
    },
    updateAge(newAge) {
      this.age = newAge
    },
    update({ name, age, role }) {
      this.name = name
      this.age = age
      this.role = role
    },
  },
})
export default useUserStore

创建大仓库 index.ts

//index.ts
import { createPinia } from 'pinia'
import { useUserStore } from './modules/user'
//创建大仓库
const pinia = createPinia()
//对外暴露:入口文件需要安装仓库
export default pinia

编写插件函数

Pinia的context和vuex不同,Pinia在使用的时候接收到的 context是仓库的上下文,每个仓库有自己的上下文,通过在控制台的输出可以看到 store中的id可以区分出来是哪个仓库,所以我们在往localStorage中存数据的时候,可以通过id 可以区分出来是哪个仓库,所以我们在往localStorage中存数据的时候,可以通过id的值做区分

//myPlugin.ts
const KEY = 'PINIA_STORE_'
const myPlugin = (context) => {
  console.log(context)
  const { store } = context
  const KEY_ = KEY + store.$id
  window.addEventListener('beforeunload', (e) => {
    localStorage.setItem(KEY_, JSON.stringify(store.$state))
  })
  const user = localStorage.getItem(KEY_)
  if (user) {
    store.$patch(JSON.parse(user))
  }
}
export default myPlugin

image.png

使用仓库

在页面使用仓库

<template>
  <div>
    <div class="store-container">
      <h2>pinia</h2>
      <n-form
        ref="formRef"
        inline
        label-width="auto"
        label-placement="left"
        :model="formJJ"
        :size="size"
      >
        <n-form-item label="姓名" path="name">
          <n-input v-model:value="formJJ.name" placeholder="输入姓名" />
        </n-form-item>
        <n-form-item label="年龄" path="age">
          <n-input v-model:value="formJJ.age" placeholder="输入年龄" />
        </n-form-item>
        <n-form-item label="角色" path="role">
          <n-input v-model:value="formJJ.role" placeholder="角色" />
        </n-form-item>
        <n-form-item>
          <n-button type="primary" attr-type="button" @click="updateJJ">
            提交
          </n-button>
        </n-form-item>
      </n-form>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import useUserStore from '@/store/modules/user'

const formRef = ref<any>()
const userStore = useUserStore()

const size = ref<'small' | 'medium' | 'large'>('medium')

const formJJ = ref<any>({
  name: undefined,
  age: undefined,
  role: undefined,
})

onMounted(() => {
  //取值
  formJJ.value = userStore.$state
})
const updateJJ = () => {
  //修改值
  userStore.update(formJJ.value)
}
</script>
<style lang="scss" scoped>
.store-container {
  width: 100%;
  height: 400px;
  margin-top: 100px;
  h2 {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    margin-bottom: 20px;
  }
}
</style>

查看状态

修改完数据之后——点击提交,然后刷新页面,数据不会丢失,说明仓库状态持久化成功了

我们是将数据存储在了 localStorage,所以要在localstorage中查看数据是否保存成功,PINIA_STORE_User 是在插件函数中 监听beforeunload 存的值

image.png