手写一个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时,建议统一进行封装,便于后续项目扩展。

相关推荐
会蹦的鱼36 分钟前
React学习day07-ReactRouter-抽象路由模块、路由导航、路由导航传参、嵌套路由、默认二级路由的设置、两种路由模式
javascript·学习·react.js
DT——5 小时前
Vite项目中eslint的简单配置
前端·javascript·代码规范
学习ing小白7 小时前
JavaWeb - 5 - 前端工程化
前端·elementui·vue
一只小阿乐7 小时前
前端web端项目运行的时候没有ip访问地址
vue.js·vue·vue3·web端
计算机学姐8 小时前
基于python+django+vue的旅游网站系统
开发语言·vue.js·python·mysql·django·旅游·web3.py
真的很上进8 小时前
【Git必看系列】—— Git巨好用的神器之git stash篇
java·前端·javascript·数据结构·git·react.js
胖虎哥er8 小时前
Html&Css 基础总结(基础好了才是最能打的)三
前端·css·html
qq_278063718 小时前
css scrollbar-width: none 隐藏默认滚动条
开发语言·前端·javascript
.ccl8 小时前
web开发 之 HTML、CSS、JavaScript、以及JavaScript的高级框架Vue(学习版2)
前端·javascript·vue.js
小徐不会写代码8 小时前
vue 实现tab菜单切换
前端·javascript·vue.js