手写一个Vuex插件优雅同步store状态与本地缓存数据

前言

下文引用一个简单的用户登录状态信息缓存例子,使用vuex中的modules选项对用户状态信息进行分模块维护的,使用plugins插件选项,注册一个用来同步state中的用户状态和本地缓存数据同步更新

了解vuex的modules和plugins选项

modules:用来解决当项目比较复杂时,单一的状态树所导致store对象变得臃肿所导致的维护困难问题,每个模块都可以拥有自己的statemutationactiongetter选项。
plugins:这个选项暴露出每次mutation的钩子。Vuex插件就是一个函数,它接收store作为唯一参数,可在该方法中监听mutation钩子的执行。

新建用户模块

store/modules/user.js

js 复制代码
import { login, logout } from '@/api/user'

const user = {
  state: () => ({
    name: '',
    avatar: '',
    token: null
  }),
  mutations: {
    setUser(state, data = {}) {
      console.log('setUser', data)
      const { name, avatar, token } = data
      state.name = name
      state.avatar = avatar
      state.token = token
    },
    removeUser(state) {
      state.name = ''
      state.avatar = ''
      state.token = null
      console.log('removeUser')
    }
  },
  actions: {
    login({commit}, data = {}) {
      const { username, password } = data
      return new Promise((resolve, reject) => {
        login(username, password).then(res => {
          commit('setUser', res)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },
    logout({state, commit}) {
      return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
          commit('removeUser')
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    }
  }
}

export default user

以上我们单独创建一个用户模块来维护和用户相关状态,分模块管理的方式对于中大型应用可以清晰地维护相关状态信息。登录和退出登录接口设计异步操作,所有我们定义在actions选项中。

注册模块

store/index.js

js 复制代码
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    user
  },
  state: {},
  mutations: {}
})

export default store

user.js模块引入到store跟实例的modules对象中。注册后,对于user模块的选项定义属性值,会和合并到store根实例中。如果需要独立隔离命名空间 ,可在user模块中添加属性namespaced: true

js 复制代码
// user.js
const user = {
  namespaced: true,
  ...
}

创建插件

store/plugins/storage.js

js 复制代码
import { setStorage, removeStorage, getStorage } from '@/utils/storage'
import { USER_KEY } from '@/utils/constant'

// 当 store 初始化后调用
const storage = store => {
  console.log('初始化')
	// 获取缓存的用户信息
  const user = getStorage(USER_KEY)
  // 用户存在,初始化用户信息
  user && store.commit('setUser', user)
  // 监听commit方法的执行
	store.subscribe((mutation, state) => {
    if(mutation.type === 'setUser') {
      setStorage(USER_KEY, state.user)
    } else if(mutation.type === 'removeUser') {
      removeStorage(USER_KEY)
    }
	})
}

export default storage;

以上我们创建了一个storage插件,用于对用户登录信息进行本地持久化和初始化。当store初始化时会调用该方法,并且参数会返回初始化后的store对象。

我们可以在该方法中对用户信息进行初始化,以及监听当执行更新用户信息的mutations方法时,自动更新本地缓存的用户信息。

引入到store跟实例并注册插件

js 复制代码
// store.js
const store = new Vuex.Store({
  // 注册插件
  plugins: [storage],
  modules: {
    user
  }
})

缓存方法封装

以下使用的时uniapp提供的本地缓存api

utils/storage.js

js 复制代码
export const setStorage = (key, data) => {
  uni.setStorageSync(key, data)
}

export const removeStorage = (key) => {
  uni.removeStorageSync(key)
}

export const getStorage = (key) => {
  const data = uni.getStorageSync(key)
  return data
}

以上我们对缓存方法的封装的目的是便于后续进行扩展,比如:

1.同一域名下如果存在多个项目,则当缓存的key属性相同时,可能会造成多个项目之间的数据污染 ,这时可在可在缓存前增加一个 项目名称前缀 等方式包装key得唯一性。

2.需要设置key的有效时间时,可以把字段包装成一个包含缓存时间的对象进行缓存。

3.当需要对缓存数据进行加密时。

4.当你要切换缓存api时。

5.其他扩展...

总结

以上通过一个简单的用户登录的例子来展开叙述,通过vuex中的modules选项对用户相关状态进行分模块维护,使用plugins选项注册一个插件,用来保证vuex中的用户状态信息和本地的缓存用户信息进行通过,在使用缓存相关api时,建议统一进行封装,便于后续项目扩展。

相关推荐
weifont2 小时前
聊一聊Electron中Chromium多进程架构
javascript·架构·electron
大得3692 小时前
electron结合vue,直接访问静态文件如何跳转访问路径
javascript·vue.js·electron
水银嘻嘻4 小时前
12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
运维·前端·自动化
it_remember4 小时前
新建一个reactnative 0.72.0的项目
javascript·react native·react.js
小嘟嚷ovo4 小时前
h5,原生html,echarts关系网实现
前端·html·echarts
十一吖i4 小时前
Vue3项目使用ElDrawer后select方法不生效
前端
只可远观4 小时前
Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
前端·flutter
周胡杰4 小时前
组件导航 (HMRouter)+flutter项目搭建-混合开发+分栏效果
前端·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
敲代码的小吉米5 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
是千千千熠啊5 小时前
vue使用Fabric和pdfjs完成合同签章及批注
前端·vue.js