Vuex-Module

由于使用單一狀態(tài)樹,應用的所有狀態(tài)會集中到一個比較大的對象。當應用變得非常復雜時写隶,store 對象就有可能變得相當臃腫玫氢。

為了解決以上問題帚屉,Vuex 允許我們將 store 分割成模塊(module)。每個模塊擁有自己的 state漾峡、mutation攻旦、action、getter生逸、甚至是嵌套子模塊——從上至下進行同樣方式的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

模塊的局部狀態(tài)

對于模塊內(nèi)部的 mutation 和 getter牢屋,接收的第一個參數(shù)是模塊的局部狀態(tài)對象。

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // 這里的 `state` 對象是模塊的局部狀態(tài)
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

同樣槽袄,對于模塊內(nèi)部的 action烙无,局部狀態(tài)通過 context.state 暴露出來,根節(jié)點狀態(tài)則為 context.rootState:

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

對于模塊內(nèi)部的 getter遍尺,根節(jié)點狀態(tài)會作為第三個參數(shù)暴露出來:

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

命名空間

默認情況下截酷,模塊內(nèi)部的 action、mutation 和 getter 是注冊在全局命名空間的——這樣使得多個模塊能夠?qū)ν?mutation 或 action 作出響應乾戏。

如果希望你的模塊具有更高的封裝度和復用性迂苛,你可以通過添加 namespaced: true 的方式使其成為命名空間模塊。當模塊被注冊后鼓择,它的所有 getter三幻、action 及 mutation 都會自動根據(jù)模塊注冊的路徑調(diào)整命名。例如:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模塊內(nèi)容(module assets)
      state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了呐能,使用 `namespaced` 屬性不會對其產(chǎn)生影響
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // 嵌套模塊
      modules: {
        // 繼承父模塊的命名空間
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // 進一步嵌套命名空間
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

啟用了命名空間的 getter 和 action 會收到局部化的 getter念搬,dispatch 和 commit。換言之催跪,你在使用模塊內(nèi)容(module assets)時不需要在同一模塊內(nèi)額外添加空間名前綴锁蠕。更改 namespaced 屬性后不需要修改模塊內(nèi)的代碼。

在命名空間模塊內(nèi)訪問全局內(nèi)容(Global Assets)

如果你希望使用全局 state 和 getter懊蒸,rootState 和 rootGetter 會作為第三和第四參數(shù)傳入 getter荣倾,也會通過 context 對象的屬性傳入 action。

若需要在全局命名空間內(nèi)分發(fā) action 或提交 mutation骑丸,將 { root: true } 作為第三參數(shù)傳給 dispatch 或 commit 即可舌仍。

modules: {
  foo: {
    namespaced: true,

    getters: {
      // 在這個模塊的 getter 中妒貌,`getters` 被局部化了
      // 你可以使用 getter 的第四個參數(shù)來調(diào)用 `rootGetters`
      someGetter (state, getters, rootState, rootGetters) {
        getters.someOtherGetter // -> 'foo/someOtherGetter'
        rootGetters.someOtherGetter // -> 'someOtherGetter'
      },
      someOtherGetter: state => { ... }
    },

    actions: {
      // 在這個模塊中, dispatch 和 commit 也被局部化了
      // 他們可以接受 `root` 屬性以訪問根 dispatch 或 commit
      someAction ({ dispatch, commit, getters, rootGetters }) {
        getters.someGetter // -> 'foo/someGetter'
        rootGetters.someGetter // -> 'someGetter'

        dispatch('someOtherAction') // -> 'foo/someOtherAction'
        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'

        commit('someMutation') // -> 'foo/someMutation'
        commit('someMutation', null, { root: true }) // -> 'someMutation'
      },
      someOtherAction (ctx, payload) { ... }
    }
  }
}

帶命名空間的綁定函數(shù)

當使用 mapState, mapGetters, mapActions 和 mapMutations 這些函數(shù)來綁定命名空間模塊時铸豁,寫起來可能比較繁瑣:

const store = new Vuex.Store({
     modules: {
        some: {
            namespaced: true,

            modules: {
                nested: {
                    namespaced: true,

                    modules: {
                        module: {   // some/nested/module
                            namespaced: true,
                            state: {
                                a: '1',
                                b: '2'
                            },
                            getters: {
                                foo :state=>state.a,
                                var: state=>state.b
                            }
                        }
                    }
                }
            }
        }
    }

})
computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  })
},
methods: {
  ...mapActions([
    'some/nested/module/foo',
    'some/nested/module/bar'
  ])
}

對于這種情況灌曙,你可以將模塊的空間名稱字符串作為第一個參數(shù)傳遞給上述函數(shù),這樣所有綁定都會自動將該模塊作為上下文节芥。于是上面的例子可以簡化為:

computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo',
    'bar'
  ])
}

而且在刺,你可以通過使用 createNamespacedHelpers 創(chuàng)建基于某個命名空間輔助函數(shù)。它返回一個對象头镊,對象里有新的綁定在給定命名空間值上的組件綁定輔助函數(shù):

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

模塊動態(tài)注冊

在 store 創(chuàng)建之后蚣驼,你可以使用store.registerModule方法注冊模塊:

// 注冊模塊 `myModule`
store.registerModule('myModule', {
  // ...
})
// 注冊嵌套模塊 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})

之后就可以通過store.state.myModulestore.state.nested.myModule訪問模塊的狀態(tài)。

模塊動態(tài)注冊功能使得其他 Vue 插件可以通過在 store 中附加新模塊的方式來使用 Vuex 管理狀態(tài)相艇。例如颖杏,vuex-router-sync插件就是通過動態(tài)注冊模塊將 vue-router 和 vuex 結(jié)合在一起,實現(xiàn)應用的路由狀態(tài)管理坛芽。

你也可以使用store.unregisterModule(moduleName)來動態(tài)卸載模塊留储。注意,你不能使用此方法卸載靜態(tài)模塊(即創(chuàng)建 store 時聲明的模塊)咙轩。

在注冊一個新 module 時获讳,你很有可能想保留過去的 state,例如從一個服務端渲染的應用保留 state臭墨。你可以通過preserveState選項將其歸檔:store.registerModule('a', module, { preserveState: true })赔嚎。

模塊重用

有時我們可能需要創(chuàng)建一個模塊的多個實例,例如:

如果我們使用一個純對象來聲明模塊的狀態(tài),那么這個狀態(tài)對象會通過引用被共享结缚,導致狀態(tài)對象被修改時 store 或模塊間數(shù)據(jù)互相污染的問題损晤。

實際上這和 Vue 組件內(nèi)的data是同樣的問題。因此解決辦法也是相同的——使用一個函數(shù)來聲明模塊狀態(tài)(僅 2.3.0+ 支持):

const MyReusableModule = {
  state () {
    return {
      foo: 'bar'
    }
  },
  // mutation, action 和 getter 等等...
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末红竭,一起剝皮案震驚了整個濱河市尤勋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茵宪,老刑警劉巖最冰,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稀火,居然都是意外死亡暖哨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門凰狞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來篇裁,“玉大人沛慢,你說我怎么就攤上這事〈锊迹” “怎么了团甲?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長黍聂。 經(jīng)常有香客問我躺苦,道長,這世上最難降的妖魔是什么产还? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任圾另,我火速辦了婚禮,結(jié)果婚禮上雕沉,老公的妹妹穿的比我還像新娘。我一直安慰自己去件,他們只是感情好坡椒,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尤溜,像睡著了一般倔叼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宫莱,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天丈攒,我揣著相機與錄音,去河邊找鬼授霸。 笑死巡验,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的碘耳。 我是一名探鬼主播显设,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼辛辨!你這毒婦竟也來了捕捂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤斗搞,失蹤者是張志新(化名)和其女友劉穎指攒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僻焚,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡允悦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溅呢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澡屡。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡猿挚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驶鹉,到底是詐尸還是另有隱情绩蜻,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布室埋,位于F島的核電站办绝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姚淆。R本人自食惡果不足惜孕蝉,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腌逢。 院中可真熱鬧降淮,春花似錦、人聲如沸搏讶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽媒惕。三九已至系吩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妒蔚,已是汗流浹背穿挨。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肴盏,地道東北人科盛。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像叁鉴,于是被迫代替她去往敵國和親土涝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 安裝 npm npm install vuex --save 在一個模塊化的打包系統(tǒng)中幌墓,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,926評論 0 7
  • Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式但壮。它采用集中式存儲管理應用的所有組件的狀態(tài),并以相應...
    白水螺絲閱讀 4,652評論 7 61
  • vuex 場景重現(xiàn):一個用戶在注冊頁面注冊了手機號碼常侣,跳轉(zhuǎn)到登錄頁面也想拿到這個手機號碼蜡饵,你可以通過vue的組件化...
    sunny519111閱讀 8,008評論 4 111
  • 上一章總結(jié)了 Vuex 的框架原理,這一章我們將從 Vuex 的入口文件開始胳施,分步驟閱讀和解析源碼溯祸。由于 Vuex...
    你的肖同學閱讀 1,768評論 3 16
  • 系列文章:Vue 2.0 升(cai)級(keng)之旅Vuex — The core of Vue applic...
    6ed7563919d4閱讀 4,541評論 2 58