一、為什么需要模塊化
前面我們講到的例子都在一個狀態樹里進行,當一個項目比較大時,所有的狀態都集中在一起會得到一個比較大的對象,進而顯得臃腫,難以維護。為了解決這個問題,Vuex允許我們將store分割成模塊(module),每個module有自己的state,mutation,action,getter,甚至還可以往下嵌套模塊,下面我們看一個典型的模塊化例子
const moduleA = {
state: {....},
mutations: {....},
actions: {....},
getters: {....}
}
const moduleB = {
state: {....},
mutations: {....},
actions: {....},
getters: {....}
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // moduleA的狀態
store.state.b // moduleB的狀態
二、模塊的局部狀態
模塊內部的mutation和getter,接收的第一參數(state)是模塊的局部狀態對象,rootState
const moduleA = {
state: { count: 0},
mutations: {
increment (state) {
// state是模塊的局部狀態,也就是上面的state
state.count++
}
},
getters: {
doubleCount (state, getters, rootState) {
// 參數 state為當前局部狀態,rootState為根節點狀態
return state.count * 2
}
},
actions: {
incremtnIfOddRootSum ( { state, commit, rootState } ) {
// 參數 state為當前局部狀態,rootState為根節點狀態
if ((state.cont + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
三、命名空間(這里一定要看,不然有些時候會被坑)
上面所有的例子中,模塊內部的action、mutation、getter是注冊在全局命名空間的,如果你在moduleA和moduleB里分別聲明了命名相同的action或者mutation或者getter(叫some),當你使用store.commit('some'),A和B模塊會同時響應。所以,如果你希望你的模塊更加自包含和提高可重用性,你可以添加namespaced: true的方式,使其成為命名空間模塊。當模塊被注冊后,它的所有getter,action,mutation都會自動根據模塊注冊的路徑調用整個命名,例如:
const store = new Vuex.Store({
modules: {
account: {
namespaced: true,
state: {...}, // 模塊內的狀態已經是嵌套的,namespaced不會有影響
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,
getters: {
popular () {...} // getters['account/posts/popular']
}
}
}
}
}
})
啟用了命名空間的getter和action會收到局部化的getter,dispatch和commit。你在使用模塊內容時不需要再同一模塊內添加空間名前綴,更改namespaced屬性后不需要修改模塊內的代碼。
四、在命名空間模塊內訪問全局內容(Global Assets)
如果你希望使用全局state和getter,roorState和rootGetter會作為第三和第四參數傳入getter,也會通過context對象的屬性傳入action若需要在全局命名空間內分發action或者提交mutation,將{ root: true }作為第三參數傳給dispatch或commit即可。
modules: {
foo: {
namespaced: true,
getters: {
// 在這個被命名的模塊里,getters被局部化了
// 你可以使用getter的第四個參數來調用 'rootGetters'
someGetter (state, getters, rootSate, rootGetters) {
getters.someOtherGetter // -> 局部的getter, ‘foo/someOtherGetter'
rootGetters.someOtherGetter // -> 全局getter, 'someOtherGetter'
}
},
actions: {
// 在這個模塊里,dispatch和commit也被局部化了
// 他們可以接受root屬性以訪問跟dispatch和commit
smoeActino ({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
}
}
}
}
五、帶命名空間的綁定函數
前面說過,帶了命名空間后,調用時必須要寫上命名空間,但是這樣就比較繁瑣,尤其涉及到多層嵌套時(當然開發中別嵌套太多,會暈。。)
下面我們看下一般寫法
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'
])
}
}
對于這種情況,你可以將模塊的命名空間作為第一個參數傳遞給上述函數,這樣所有的綁定會自動將該模塊作為上下文。簡化寫就是
computed: {
...mapStates('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module',[
'foo',
'bar'
])
}
六、模塊重用
有時我們可能創建一個模塊的多個實例,例如:
如果我們使用一個純對象來聲明模塊的狀態,那么這個狀態對象會通過引用被共享,導致數據互相污染。
實際上Vue組件內data是同樣的問題,因此解決辦法也是一樣的,使用一個函數來聲明模塊狀態(2.3.0+支持)
const MyModule = {
state () {
return {
foo: 'far'
}
}
}
七、總結
到這里模塊化(module)的內容就已經講完了,本次主要講解了module出現的原因,使用方法,全局和局部namespaced模塊命名空間,局部訪問全局內容,map函數帶有命名空間的綁定函數和模塊的重用。
引用
https://vuex.vuejs.org Vuex官方文檔
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。