由于Vuex的官方文檔在各個(gè)模塊之間缺乏一些過(guò)渡塞关,另外新概念很多,使得初讀時(shí)總有些云里霧里的感覺(jué)。于是本文在官方文檔的基礎(chǔ)上補(bǔ)充了一些自己的理解及相關(guān)的背景知識(shí)璧眠,尤其是試圖讓各個(gè)部分之間形成一定的連貫關(guān)系足陨。希望能幫助初學(xué)者更快地理解Vuex嫂粟。
一、Vuex是干什么用的墨缘?
它是用于對(duì)復(fù)雜應(yīng)用進(jìn)行狀態(tài)管理用的(官方說(shuō)法是它是一種狀態(tài)管理模式)星虹。
“殺雞不用宰牛刀”。對(duì)于簡(jiǎn)單的項(xiàng)目镊讼,根本用不著Vuex這把“宰牛刀”宽涌。那簡(jiǎn)單的項(xiàng)目用什么呢?用Vue.js官方提供的事件總線就可以了蝶棋。
二护糖、我們import進(jìn)來(lái)的Vuex對(duì)象都包含些什么呢?
我們使用Vuex的時(shí)候怎么用呢嚼松?通常都是這樣:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
new Vuex.Store({
state: { //放置state的值
count: 0,
str:"abcd234"
},
getters: { //放置getters方法
strLen: state => state.str.length
},
// mutations只能是同步操作
mutations: { //放置mutations方法
increment(state, payload) {
//在這里改變state中的數(shù)據(jù)
state.count = payload.number;
}
},
// actions可以是異步操作
actions: { //放置actions方法
actionName({ commit }) {
//dosomething
commit('mutationName')
},
getSong ({commit}, id) {
api.getMusicUrlResource(id).then(res => {
let url = res.data.data[0].url;
})
.catch((error) => { // 錯(cuò)誤處理
console.log(error);
});
}
}
});
new Vue({
el: '#app',
store,
...
});
這里import進(jìn)來(lái)的Vuex是個(gè)什么東西呢嫡良?我們用console.log
把它輸出一下:
console.log(Vuex)
通過(guò)輸出,我們發(fā)現(xiàn)其結(jié)構(gòu)如下:
{
? Store: function Store(){},
? mapActions: function(){}, // 對(duì)應(yīng)Actions的結(jié)果集
? mapGetters: function(){}, // 對(duì)應(yīng)Getters的結(jié)果集
? mapMutations: function(){}, // 對(duì)應(yīng)Mutations的結(jié)果集
? mapState: function(){}, // 對(duì)應(yīng)State的結(jié)果集
? install: function install(){},
? installed: true
}
可見(jiàn)献酗,import進(jìn)來(lái)的Vuex它實(shí)際上是一個(gè)對(duì)象寝受,里面包含了Store這一構(gòu)造函數(shù),還有幾個(gè)mapActions罕偎、mapGetters很澄、mapMutations、mapState這幾個(gè)輔助方法(后面再講)。
除此之外甩苛,還有一個(gè)install
方法蹂楣。我們發(fā)現(xiàn),import之后要對(duì)其進(jìn)行Vue.use(Vuex);
的操作讯蒲。根據(jù)這兩個(gè)線索痊土,我們就明白了,Vuex本質(zhì)上就是一個(gè)Vue.js的插件墨林。不信你去對(duì)照下Vue.js的官方文檔中對(duì)于插件的解釋就知道了(見(jiàn)這里)赁酝。
三、創(chuàng)建好的store實(shí)例怎么在各個(gè)組件中都能引用到旭等?
new Vuex.Store實(shí)例酌呆,怎么才能在各個(gè)組件中都能引用到呢?因?yàn)檫@個(gè)store實(shí)例是個(gè)全局單例搔耕。Vuex 通過(guò) store
選項(xiàng)隙袁,提供了一種機(jī)制將狀態(tài)從根組件“注入”到每一個(gè)子組件中:
const app = new Vue({
el: '#app',
// 把 store 對(duì)象提供給 “store” 選項(xiàng),這可以把 store 的實(shí)例注入所有的子組件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
通過(guò)在根實(shí)例中注冊(cè) store
選項(xiàng)弃榨,該 store 實(shí)例會(huì)注入到根組件下的所有子組件中藤乙,且子組件能通過(guò) this.$store
訪問(wèn)到。
四惭墓、Vuex中的幾大核心概念
1、State
這個(gè)很好理解而姐,就是狀態(tài)數(shù)據(jù)腊凶。Vuex所管理的就是狀態(tài),其它的如Actions拴念、Mutations都是來(lái)輔助實(shí)現(xiàn)對(duì)狀態(tài)的管理的钧萍。Vue組件要有所變化,也是直接受到State的驅(qū)動(dòng)來(lái)變化的政鼠。
可以通過(guò)this.$store.state來(lái)直接獲取狀態(tài)风瘦,也可以利用vuex提供的mapState輔助函數(shù)將state映射到計(jì)算屬性(computed)中去。
mapState
輔助函數(shù)
當(dāng)一個(gè)組件需要獲取多個(gè)狀態(tài)時(shí)候公般,將這些狀態(tài)都聲明為計(jì)算屬性會(huì)有些重復(fù)和冗余万搔。為了解決這個(gè)問(wèn)題,我們可以使用 mapState
輔助函數(shù)幫助我們生成計(jì)算屬性官帘,讓你少按幾次鍵:
// 在單獨(dú)構(gòu)建的版本中輔助函數(shù)為 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭頭函數(shù)可使代碼更簡(jiǎn)練
count: state => state.count,
// 傳字符串參數(shù) 'count' 等同于 `state => state.count`
countAlias: 'count',
// 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
當(dāng)映射的計(jì)算屬性的名稱與 state 的子節(jié)點(diǎn)名稱相同時(shí),我們也可以給 mapState
傳一個(gè)字符串?dāng)?shù)組褥蚯。
computed: mapState([
// 映射 this.count 為 store.state.count
'count'
])
2拔创、Getters
Getters本質(zhì)上是用來(lái)對(duì)狀態(tài)進(jìn)行加工處理。Getters與State的關(guān)系,就像Vue.js的computed與data的關(guān)系胖缤。getter 的返回值會(huì)根據(jù)它的依賴被緩存起來(lái)尚镰,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算。
可以通過(guò)this.$store.getters.valueName對(duì)派生出來(lái)的狀態(tài)進(jìn)行訪問(wèn)哪廓」钒Γ或者直接使用輔助函數(shù)mapGetters將其映射到本地計(jì)算屬性中去。
mapGetters
輔助函數(shù)
mapGetters
輔助函數(shù)僅僅是將 store 中的 getter 映射到局部計(jì)算屬性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用對(duì)象展開(kāi)運(yùn)算符將 getter 混入 computed 對(duì)象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
如果你想將一個(gè) getter 屬性另取一個(gè)名字撩独,使用對(duì)象形式:
mapGetters({
// 映射 `this.doneCount` 為 `store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
上面這段代碼中敞曹,有個(gè)寫法大家可能會(huì)奇怪,就是...mapGetters
综膀。這是什么鬼東西呢澳迫?
其中mapGetters實(shí)際上是一個(gè)方法Vuex對(duì)象上的一個(gè)方法,這從本文開(kāi)頭打印的那個(gè)Vuex對(duì)象的內(nèi)容可以看出來(lái)剧劝¢系牵…這個(gè)符號(hào)是ES2015的一個(gè)新的語(yǔ)法糖,即將mapGetters處理后的內(nèi)容展開(kāi)后填入讥此。
3拢锹、Mutations
Mutations的中文意思是“變化”,利用它可以更改狀態(tài)萄喳。事實(shí)上卒稳,更改 Vuex 的 store 中的狀態(tài)的唯一方法就是提交 (commit)mutation。不過(guò)他巨,mutation觸發(fā)狀態(tài)改變的方式有一點(diǎn)特別充坑,所謂commit一個(gè)mutation,實(shí)際是像觸發(fā)一個(gè)事件一樣染突,傳入一個(gè)mutation的類型以及攜帶一些數(shù)據(jù)(稱作payload捻爷,載荷)。
本文開(kāi)頭那段代碼中所指明的mutations份企,即:
mutations: { //放置mutations方法
increment(state, payload) {
//在這里改變state中的數(shù)據(jù)
state.count = payload.number;
}
},
其中所包含的也榄,實(shí)際上是一個(gè)個(gè)的mutation處理函數(shù),用于指明收到這個(gè)mutation的commit之后司志,應(yīng)該做些什么(當(dāng)然甜紫,主要就是改變state,只是改變哪些state值的問(wèn)題)骂远。
那commit一個(gè)mutation在代碼層面怎么表示呢棵介?
this.$store.commit('increment', {
amount: 10
})
或者這樣:
this.$store.commit({
type: 'increment',
amount: 10
})
除了這種使用 this.$store.commit('xxx')
提交 mutation的方式之外,還有一種方式吧史,即使用 mapMutations
輔助函數(shù)將組件中的 methods 映射為 this.$store.commit
邮辽。例如:
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
// `mapMutations` 也支持載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
})
}
}
經(jīng)過(guò)這樣的映射之后唠雕,就可以通過(guò)調(diào)用方法的方式來(lái)觸發(fā)其對(duì)應(yīng)的(所映射到的)mutation commit了,比如吨述,上例中調(diào)用add()方法岩睁,就相當(dāng)于執(zhí)行了this.$store.commit('increment')
了。
像上面這樣揣云,就既聲明了收到mutation后怎么處理捕儒,又清楚了怎么觸發(fā)一個(gè)mutation。是不是特別像事件的處理函數(shù)(handler)以及事件的觸發(fā)(emit)之間的關(guān)系邓夕?
考慮到觸發(fā)的mutation的type必須與mutations里聲明的mutation名稱一致刘莹,比較好的方式是把這些mutation都集中到一個(gè)文件(如mutation-types)中以常量的形式定義,在其它地方再將這個(gè)文件引入焚刚,便于管理点弯。而且這樣做還有一個(gè)好處,就是整個(gè)應(yīng)用中一共有哪些mutation type可以一目了然矿咕。就像下面這樣:
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// 我們可以使用 ES2015 風(fēng)格的計(jì)算屬性命名功能來(lái)使用一個(gè)常量作為函數(shù)名
[SOME_MUTATION] (state) {
// mutate state
}
}
})
值得注意的是抢肛,mutation必須是同步函數(shù),目的是為了在dev-tools中能夠捕捉到每一條mutation前后狀態(tài)的快照(參見(jiàn)https://www.zhihu.com/question/48759748)碳柱。
4捡絮、Actions
與必須是同步函數(shù)Mutation所不同,Action可以包含異步的操作莲镣。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
或者用ES2015的參數(shù)解構(gòu)福稳,可以簡(jiǎn)寫成:
actions: {
increment ({commit}) {
commit('increment')
}
}
和mutation類似,我們像上面這樣生命action的處理函數(shù)瑞侮。它接收的第一個(gè)參數(shù)是一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對(duì)象的圆,因此你可以調(diào)用 context.commit
提交一個(gè) mutation,或者通過(guò) context.state
和 context.getters
來(lái)獲取 state 和 getters区岗。
不過(guò),mutation處理函數(shù)中所做的事情是改變state毁枯,而action處理函數(shù)中所做的事情則是commit mutation慈缔。
那么,怎么觸發(fā)action呢种玛?按照Vuex的叫法藐鹤,這叫分發(fā)(dispatch),我覺(jué)得這個(gè)名字讓人不好理解赂韵,我們反正知道它實(shí)際上是觸發(fā)的意思就行了娱节。具體的觸發(fā)方法是this.$store.dispatch(actionType, payload)
。所傳的兩個(gè)參數(shù)一個(gè)是要觸發(fā)的action的類型祭示,一個(gè)是所攜帶的數(shù)據(jù)(payload)肄满,類似于上文所講的commit mutation時(shí)所傳的那兩個(gè)參數(shù)。具體如下:
// 以載荷形式分發(fā)
this.$store.dispatch('incrementAsync', {
amount: 10
})
或
// 以對(duì)象形式分發(fā)
this.$store.dispatch({
type: 'incrementAsync',
amount: 10
})
還有一種方法是使用 mapActions
輔助函數(shù)將組件的 methods 映射為 this.$store.dispatch
調(diào)用。如下:
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')`
// `mapActions` 也支持載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')`
})
}
}
另外稠歉,你需要知道掰担, this.$store.dispatch
可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise,并且 this.$store.dispatch
仍舊返回 Promise怒炸。
再來(lái)看一些組合性的異步操作:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
現(xiàn)在你可以:
$this.store.dispatch('actionA').then(() => {
// ...
})
在另外一個(gè) action 中也可以:
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
最后带饱,如果我們利用 async / await 這個(gè) JavaScript 即將到來(lái)的新特性,我們可以像這樣組合 action:
// 假設(shè) getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
這實(shí)際上就實(shí)現(xiàn)了action嵌套另一個(gè)action的情況阅羹。
講了這么多action勺疼,你可能會(huì)納悶一個(gè)問(wèn)題:action這鬼東西不是和mutation看起來(lái)好多地方都很像嗎,直接觸發(fā)mutation去改變state豈不更好捏鱼?為什么還要先觸發(fā)action执庐,再由action去觸發(fā)mutation才達(dá)到改變state的目的?
這是個(gè)好問(wèn)題穷躁。還記得上面我們提到過(guò)mutation只能是同步的操作而action可以是包含異步操作嗎耕肩?那么,若想進(jìn)行異步操作问潭,通過(guò)mutation顯然是無(wú)法完成的猿诸,所以就有了action。我們來(lái)看一個(gè)更加實(shí)際的購(gòu)物車示例狡忙,涉及到調(diào)用異步 API 和分發(fā)多重 mutation:
actions: {
checkout ({ commit, state }, products) {
// 把當(dāng)前購(gòu)物車的物品備份起來(lái)
const savedCartItems = [...state.cart.added]
// 發(fā)出結(jié)賬請(qǐng)求梳虽,然后樂(lè)觀地清空購(gòu)物車
commit(types.CHECKOUT_REQUEST)
// 購(gòu)物 API 接受一個(gè)成功回調(diào)和一個(gè)失敗回調(diào)
shop.buyProducts(
products,
// 成功操作
() => commit(types.CHECKOUT_SUCCESS),
// 失敗操作
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
5、Module
Module是什么概念呢灾茁?它實(shí)際上是對(duì)于store的一種切割窜觉。由于Vuex使用的是單一狀態(tài)樹(shù),這樣整個(gè)應(yīng)用的所有狀態(tài)都會(huì)集中到一個(gè)比較大的對(duì)象上面北专,那么禀挫,當(dāng)應(yīng)用變得非常復(fù)雜時(shí),store 對(duì)象就很可能變得相當(dāng)臃腫拓颓!
為了解決以上問(wèn)題语婴,Vuex 允許我們將 store 分割成一個(gè)個(gè)的模塊(module)。每個(gè)模塊擁有自己的 state驶睦、mutation砰左、action、getter场航、甚至是嵌套子模塊——從上至下進(jìn)行同樣方式的分割缠导。就像這樣:
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)
對(duì)于每個(gè)模塊內(nèi)部的 mutation 和 getter,接收的第一個(gè)參數(shù)就是模塊的局部狀態(tài)對(duì)象溉痢。
const moduleA = {
state: { count: 0 },
mutations: {
increment (state) {
// 這里的 `state` 對(duì)象是模塊的局部狀態(tài)
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
同樣僻造,對(duì)于模塊內(nèi)部的 action憋他,局部狀態(tài)通過(guò) context.state
暴露出來(lái),根節(jié)點(diǎn)狀態(tài)則為 context.rootState
:
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
對(duì)于模塊內(nèi)部的 getter嫡意,根節(jié)點(diǎn)狀態(tài)會(huì)作為第三個(gè)參數(shù)暴露出來(lái):
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
命名空間
默認(rèn)情況下举瑰,模塊內(nèi)部的 action、mutation 和 getter 是注冊(cè)在全局命名空間的——這樣使得多個(gè)模塊能夠?qū)ν?mutation 或 action 作出響應(yīng)蔬螟。
如果希望你的模塊具有更高的封裝度和復(fù)用性此迅,你可以通過(guò)添加 namespaced: true
的方式使其成為命名空間模塊。當(dāng)模塊被注冊(cè)后旧巾,它的所有 getter耸序、action 及 mutation 都會(huì)自動(dòng)根據(jù)模塊注冊(cè)的路徑調(diào)整命名。例如:
const store = new Vuex.Store({
modules: {
account: {
namespaced: true,
// 模塊內(nèi)容(module assets)
state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了鲁猩,使用 `namespaced` 屬性不會(huì)對(duì)其產(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']
}
},
// 進(jìn)一步嵌套命名空間
posts: {
namespaced: true,
state: { ... },
getters: {
popular () { ... } // -> getters['account/posts/popular']
}
}
}
}
}
})
啟用了命名空間的 getter 和 action 會(huì)收到局部化的 getter
坎怪,dispatch
和 commit
。
在命名空間模塊內(nèi)訪問(wèn)全局內(nèi)容(Global Assets)
如果你希望使用全局 state 和 getter廓握,rootState
和 rootGetter
會(huì)作為第三和第四參數(shù)傳入 getter搅窿,也會(huì)通過(guò) context
對(duì)象的屬性傳入 action。
若需要在全局命名空間內(nèi)分發(fā) action 或提交 mutation隙券,將 { root: true }
作為第三參數(shù)傳給 dispatch
或 commit
即可男应。
modules: {
foo: {
namespaced: true,
getters: {
// 在這個(gè)模塊的 getter 中,`getters` 被局部化了
// 你可以使用 getter 的第四個(gè)參數(shù)來(lái)調(diào)用 `rootGetters`
someGetter (state, getters, rootState, rootGetters) {
getters.someOtherGetter // -> 'foo/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'
},
someOtherGetter: state => { ... }
},
actions: {
// 在這個(gè)模塊中娱仔, dispatch 和 commit 也被局部化了
// 他們可以接受 `root` 屬性以訪問(wèn)根 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ù)
當(dāng)使用 mapState
, mapGetters
, mapActions
和 mapMutations
這些函數(shù)來(lái)綁定命名空間模塊時(shí)沐飘,寫起來(lái)可能比較繁瑣:
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'
])
}
對(duì)于這種情況,你可以將模塊的空間名稱字符串作為第一個(gè)參數(shù)傳遞給上述函數(shù)牲迫,這樣所有綁定都會(huì)自動(dòng)將該模塊作為上下文耐朴。于是上面的例子可以簡(jiǎn)化為:
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo',
'bar'
])
}
而且,你可以通過(guò)使用 createNamespacedHelpers
創(chuàng)建基于某個(gè)命名空間輔助函數(shù)盹憎。它返回一個(gè)對(duì)象筛峭,對(duì)象里有新的綁定在給定命名空間值上的組件綁定輔助函數(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'
])
}
}
給插件開(kāi)發(fā)者的注意事項(xiàng)
如果你開(kāi)發(fā)的插件(Plugin)提供了模塊并允許用戶將其添加到 Vuex store,可能需要考慮模塊的空間名稱問(wèn)題陪每。對(duì)于這種情況影晓,你可以通過(guò)插件的參數(shù)對(duì)象來(lái)允許用戶指定空間名稱:
// 通過(guò)插件的參數(shù)對(duì)象得到空間名稱
// 然后返回 Vuex 插件函數(shù)
export function createPlugin (options = {}) {
return function (store) {
// 把空間名字添加到插件模塊的類型(type)中去
const namespace = options.namespace || ''
store.dispatch(namespace + 'pluginAction')
}
}
模塊動(dòng)態(tài)注冊(cè)
在 store 創(chuàng)建之后,你可以使用 store.registerModule
方法注冊(cè)模塊:
// 注冊(cè)模塊 `myModule`
store.registerModule('myModule', {
// ...
})
// 注冊(cè)嵌套模塊 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
// ...
})
之后就可以通過(guò) store.state.myModule
和 store.state.nested.myModule
訪問(wèn)模塊的狀態(tài)奶稠。
模塊動(dòng)態(tài)注冊(cè)功能使得其他 Vue 插件可以通過(guò)在 store 中附加新模塊的方式來(lái)使用 Vuex 管理狀態(tài)俯艰。例如捡遍,vuex-router-sync
插件就是通過(guò)動(dòng)態(tài)注冊(cè)模塊將 vue-router 和 vuex 結(jié)合在一起锌订,實(shí)現(xiàn)應(yīng)用的路由狀態(tài)管理。
你也可以使用 store.unregisterModule(moduleName)
來(lái)動(dòng)態(tài)卸載模塊画株。注意辆飘,你不能使用此方法卸載靜態(tài)模塊(即創(chuàng)建 store 時(shí)聲明的模塊)啦辐。
模塊重用
有時(shí)我們可能需要?jiǎng)?chuàng)建一個(gè)模塊的多個(gè)實(shí)例,例如:
- 創(chuàng)建多個(gè) store蜈项,他們公用同一個(gè)模塊
- 在一個(gè) store 中多次注冊(cè)同一個(gè)模塊
如果我們使用一個(gè)純對(duì)象來(lái)聲明模塊的狀態(tài)芹关,那么這個(gè)狀態(tài)對(duì)象會(huì)通過(guò)引用被共享,導(dǎo)致?tīng)顟B(tài)對(duì)象被修改時(shí) store 或模塊間數(shù)據(jù)互相污染的問(wèn)題紧卒。
實(shí)際上這和 Vue 組件內(nèi)的 data
是同樣的問(wèn)題侥衬。因此解決辦法也是相同的——使用一個(gè)函數(shù)來(lái)聲明模塊狀態(tài)(僅 2.3.0+ 支持):
const MyReusableModule = {
state () {
return {
foo: 'bar'
}
},
// mutation, action 和 getter 等等...
}