美文网首页
层次和约束:项目中使用vuex的3条优化方案

层次和约束:项目中使用vuex的3条优化方案

作者: 凌霄光 | 来源:发表于2018-10-22 17:01 被阅读110次

    问题描述

    使用vuex的store的过程中,发现了一些不是很优雅的地方:

    1. store层module太多,找state、getter、mutation、action对应的module比较慢。
    1. 组件里面mapGetters、mapActions、mapMutations过多,分不清getter、action、mutation属于哪个module,比较混乱。
    1. 没有使用mutation type 和action type的枚举常量来约束action type和mutation type取值,字符串方式容易出错。(如上图)

    解决方案

    针对这3个问题,制定了3条重构方案。

    1. module聚类分层

    按照聚类分层思想,当业务复杂后,需要通过一定的聚类特征对扁平化的结构进行分层。

    这里按照数据的用途分了page、components、domain、other这四类,page存储页面组件的数据,components存储基础组件的数据,domain存储实体的数据,other存储其他全局数据。

    之前的modules

    之后的modules



    目前还没有存储实体数据的module,所以暂时为空

    2.module添加namespace

    store划分module是因为不同的数据有不同的归属。

    如果想要每个module都能响应全局action的话,不需要加namespace,但是我们并没有没有一个action对应多个module的action handler的情况。反而因为没有加namespace,导致组件里的多个module的getter、action、mutation都扁平的堆在一起,结构混乱、不清晰。

        ...mapMutations([
          changeisIceTree: 'changeisIceTree',
          changeIceTreeStatus: 'changeIceTreeStatus',
          showToast: 'showToast',
          changeremainingfronzeTime: 'changeremainingfronzeTime',
          decreaseremainingfronzeTime: 'decreaseremainingfronzeTime',
          changeiceTreeFadeout: 'changeiceTreeFadeout',
          changeiceTreeFadeIn: 'changeiceTreeFadeIn',
          changefrozenTimes: 'changefrozenTimes',
          changetreecurTime: 'changetreecurTime',
          changequickTreeMedal:'changequickTreeMedal',
          changequickHonorMedal:"changequickHonorMedal",
          upDatePopUpOptionStatus: 'upDatePopUpOptionStatus'
        }),
    

    一堆的mutation让人迷惑,结构很不清晰,哪个mutation是哪个module必须去store中找。

    加上namespace之后,每个mutaion属于一个namespace,每个namespace代表一个module,在组件里就可以轻松的根据namespace区分出哪个module来。

    ...mapGetters('aaaaa',[
       'mutation111111',
       'mutation22222',
       'mutation33333'
    ]);
    ...mapMutations('aaaaa',[
       'mutation111111',
       'mutation22222',
       'mutation33333'
    ]);
    ...mapMutations('bbbbb',[
       'mutation4444444',
       'mutation555555',
       'mutation666666',
    ]);
    

    这样重构之后,组件用到再多module的action、getter、mutation也不会混乱了。

    3.mutation type和action type使用枚举常量约束

    mutation type和action type的名字可能会写错,因为没有使用typescript,没有类型约束,如果写错了,编译时无法检查出来,只能在运行时检查。解决这个问题或者使用ts,或者全部的mutation type和action type从枚举常量中取。

    store中的数据是模块化的,mutation type 和action type的枚举常量自然也是,但是vuex的module并不会处理这两者,想把这些模块化的motation type和action type挂到store实例上,可以通过vuex插件来解决。

    我发现社区并没有我需要的vuex插件,于是我自己封装了一个

    /**
     * 生成文件对应的模块
     * 
     * @param {*} dirPath 文件夹路径
     */
    const generateModules = (files) => {
        const modules = {}
    
        files.keys().forEach(key => {
            modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
        })
        return modules;
    }
    
    
    /**
     * 所有file
     * 
     */
    const allFiles = {
        page: require.context('../modules/page', false, /\.js$/),
        components: require.context('../modules/components', false, /\.js$/),
        domain: require.context('../modules/domain', false, /\.js$/),
        other: require.context('../modules/other', false, /\.js$/)
    }
    
    /**
     * 所有module
     * 
     */
    const allModules = {
        page: generateModules(allFiles.page),
        components: generateModules(allFiles.components),
        domain: generateModules(allFiles.domain),
        other: generateModules(allFiles.other)
    }
    
    
    /**
     * 根据types获取modules下的多个模块的结构化数据
     * @param {*} types module type
     * @param {*} fieldName 字段名
     */
    const getStructuredData = (types, fieldNames) => {
        const structuredData = {};
        types.forEach(type => {
            const modules = allModules[type];
            const structuredModuleData = Object.keys(modules).map(moduleName => {
                const fields = fieldNames.map(fieldName => modules[moduleName][fieldName])
                return {
                    [moduleName]: Object.assign(...fields)
                }
            });
            structuredData[type]= structuredModuleData && structuredModuleData.length ? Object.assign(...structuredModuleData): {};
        })
        return structuredData
    }
    
    
    const enumTypePlugin = store => {
    
        const mutationTypeEnum = getStructuredData(['page','components','domain','other'], ['mutationTypes']);
        const actionTypeEnum = getStructuredData(['page','components','domain','other'], ['actionTypes']);
    
        store.mutationTypes = mutationTypeEnum;
        store.actionTypes = actionTypeEnum;
    }
    module.exports = enumTypePlugin;
    

    添加到vuex的plugins中

    import typeEnumPlugin from './type-enum-plugin';
    
    new Vuex.Store(
      modules,
      plugins: [typeEnumPlugin]
    )
    

    module定义时导出mutation types和action types

    module.exports = {
       state,
       getters,
       mutations,
       actions,
       mutationTypes,
       actionTypes
    }
    

    在组件里面就可以使用action type和mutation type来mapAction,mapMutation

    ...mapActions({
      mutation1: this.$store.mutationTypes.page.aaa.mutation1,
      mutation2: this.$store.mutationTypes.page.aaa.mutation2,
      mutation3: this.$store.mutationTypes.page.aaa.mutation3
    })
    ...mapActions({
      action1: this.$store.actionTypes.page.aaa.action1,
      action2: this.$store.actionTypes.page.aaa.action2,
      action3: this.$store.actionTypes.page.aaa.action3
    })
    

    或者像下面这样全部导入

    ...mapMutations(this.$store.mutationTypes.page.aaa)
    ...mapActions(this.$store.actionTypes.page.aaa)
    

    这样就避免了手写字符串可能出错的问题。

    总结

    针对vuex store的module过多,组件里无法区分出getter、action、mutation属于哪一个module,mutation type和action type无约束这3个问题,针对性的提出了3条解决方案:

    module聚类分层,分成page、components、domain、other四个文件夹存放module;

    添加namespace,组件中使用mapGetters、mapActions、mapMuatations时加上namespace区分;

    module定义时导出mutation types和action types,并通过vuex的插件挂到store上,组件中使用mapMutations和mapActions不再通过字符串取对应值。

    相关文章

      网友评论

          本文标题:层次和约束:项目中使用vuex的3条优化方案

          本文链接:https://www.haomeiwen.com/subject/sjxgzftx.html