層次和約束:項目中使用vuex的3條優化方案

問題描述

使用vuex的store的過程當中,發現了一些不是很優雅的地方:javascript

  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條重構方案。vue

1. module聚類分層

按照聚類分層思想,當業務複雜後,須要經過必定的聚類特徵對扁平化的結構進行分層。java

這裏按照數據的用途分了page、components、domain、other這四類,page存儲頁面組件的數據,components存儲基礎組件的數據,domain存儲實體的數據,other存儲其餘全局數據。vuex

以前的modulestypescript

以後的modules bash

目前尚未存儲實體數據的module,因此暫時爲空

2.module添加namespace

store劃分module是由於不一樣的數據有不一樣的歸屬。dom

若是想要每一個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中找。post

加上namespace以後,每一個mutaion屬於一個namespace,每一個namespace表明一個module,在組件裏就能夠輕鬆的根據namespace區分出哪一個module來。ui

...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再也不經過字符串取對應值。

相關文章
相關標籤/搜索