重构store结构

157 阅读3分钟

以前的项目使用了modules做了store的结构调整,现在大多数项目也是这种结构。

 ├── mutation-types.js
 ├── module
    ├── actions
    │   └── index.js
    ├── mutations
    │   └── index.js
    ├── state
    │   └── index.js
 └── store
        └── index.js

但是随着项目越来越大,用起来觉得确实有点别扭了,(当你觉得别扭的时候,只能表明你的代码还有很大的优化空间)这可能就是所谓的码感,比如引入module的时候,每个module都要导入一遍,比如存储storage的时候,都是set,get却要重复使用,而且都放在mutations里面看上去太乱了,等等.....这些都是优化的点。

说干就干,程序员的脾气就是这样

一. modules的引入

以前我们的代码是这样

import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
import check from "./module/check.js"
import maintain from "./module/maintain"
import user from "./module/user.js"
import machineStatus from "./module/machineStatus.js"

const store = new Vuex.Store({
    getters: {
	userInfo:state=>state.user.userInfo,
	loginInfo:state=>state.user.loginInfo,
	UserEId:state=>state.user.UserEId
    },
    modules:{
	check,
	user,
	maintain,
	machineStatus
    }
})
export default store

试想一下,如果有多个modules,我们岂不是得引到猴年马月......,可不可以用一个工具帮我们自动引入module文件下的所有js文件呢?emmm,当然可以

  • require.context(路径,是否包含子目录,文件名格式)获取指定目录下的文件

  • context(fileName)获取指定文件名的文件

import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)

const context = require.context('./module', true, /\.js$/);
console.log(context.keys())
let modules={}
context.keys().forEach((fileName)=>{
	let key=fileName.replace(/(^\.\/)|(\.js$)/ig,"")
	modules[key]=context(fileName).default
})

const store = new Vuex.Store({
    getters: {
	userInfo:state=>state.user.userInfo,
	loginInfo:state=>state.user.loginInfo,
	UserEId:state=>state.user.UserEId
    },
    modules
})
export default store

妈呀,像变魔术一样,也太简洁了。

二. 制定持久化plugin

最开始的想法是通过switch来判断每次mutation的type,然后去存储,如果payload为空表示要从本地删除存储。

// import store from "./store"
import storage from "@/util/storage"
import hUtils from "@/util"
//统一管理localStorage,只是监听不是拦截操作

const storePlugin=()=>store=>{
	store.subscribe((mutation,state)=>{
		let {type,payload}=mutation;
		let finalType
		if(type.indexOf("/")>=0){
			finalType=type.split("/")[1]
		}
		else{
			finalType=type
		}
		switch(finalType){
			case "SET_USEREID":
			storage.set("UserEId", payload);
			if (!payload){
				storage.remove("UserEId")
			};
			break;
			case "SET_LOGININFO":
			storage.set("loginInfo", payload);
			if (hUtils.isEmptyObj(payload)){
				storage.remove("loginInfo")
			};
			break;
			case "SET_USERINFO":
			storage.set("userInfo", payload)
			if (hUtils.isEmptyObj(payload)) {
				storage.remove("userInfo")
			};
			break;
			case "SET_CURRENTMACHINE":
			storage.set("currentMachine",payload);
			break;
			case "SET_CURRENTMACHINEINDEX":
			storage.set("currentMachineIndex",payload);
			break;		
			default:"";break;
		}
	})
}
export default storePlugin

但这种写法也有点累赘,后来参考了一篇博客,可以将它做成store中的插件,通过plugins这个参数来调用。并对匹配进行了优化,因为每个switch之后的操作都一样。

首先写一个工具函数判断是否为空,依次判断是否去删除本地存储

isEmpty.js

"",null,undefined,[],{}都表示为空,把0排除掉

isEmpty(value){
    if(!value&&value!==0){
	return true
    }
    else{
	if(Object.prototype.toString.call(value)==="[object Array]"){
		return value.length===0
	}
		if(Object.prototype.toString.call(value)==="[object Object]"){
			return Object.keys(value).length === 0
	}
    }
    return false
}

改造后的plugin插件

import storage from "@/util/storage"
import hUtils from "@/util"
//统一管理localStorage,只是监听不是拦截操作

const storePlugin=()=>store=>{
	store.subscribe((mutation,state)=>{
		const storageObj={
			["SET_USEREID"]:"UserEId",
			["SET_LOGININFO"]:"loginInfo",
			["SET_USERINFO"]:"userInfo",
			["SET_CURRENTMACHINE"]:"currentMachine",
			["SET_CURRENTMACHINEINDEX"]:"currentMachineIndex"
		}//格式为mutation的键值和state的键值
		let {type,payload}=mutation;
		let finalType
		if(type.indexOf("/")>=0){
			finalType=type.split("/")[1]
		}
		else{
			finalType=type
		}
		//将匹配到的值存储到storage中
		if(Object.keys(storageObj).includes(finalType)){
			console.log(finalType)
			storage.set(storageObj[finalType],payload)
			if(hUtils.isEmpty(payload)){
				storage.remove(storageObj[finalType])
			}
		}
	})
}
export default storePlugin

在store中调用

const store = new Vuex.Store({
    plugins:[MyPlugin()],
    getters: {
	userInfo:state=>state.user.userInfo,
	loginInfo:state=>state.user.loginInfo,
	UserEId:state=>state.user.UserEId
    },
    modules:{
	check,
	user,
	maintain,
	machineStatus
    }
})

后续优化,实现state从缓存中自动化获取

参考博客

vue技巧

持久化插件 

require.context的使用

简化路由引入