核心概念
Vuex 是適用于 Vue.js 應(yīng)用的狀態(tài)管理庫,為應(yīng)用中的所有組件提供集中式的狀態(tài)存儲與操作,保證了所有狀態(tài)以可預(yù)測的方式進(jìn)行修改。

- Vue Components:Vue組件。HTML頁面上,負(fù)責(zé)接收用戶操作等交互行
為,執(zhí)行dispatch方法觸發(fā)對應(yīng)action進(jìn)行回應(yīng)。 - dispatch:操作行為觸發(fā)方法,是唯一能執(zhí)行action的方法。
- actions:操作行為處理模塊。負(fù)責(zé)處理Vue Components接收到的所有交互行為。包含同步/異步操作,支持多個同名方法,按照注冊的順序依次觸發(fā)。向后臺API請求的操作就在這個模塊中進(jìn)行,包括觸發(fā)其他action以及提交mutation的操作。該模塊提供了Promise的封裝,以支持action的鏈?zhǔn)接|發(fā)。
- commit:狀態(tài)改變提交操作方法。對mutation進(jìn)行提交,是唯一能執(zhí)行mutation的方法。
- mutations:狀態(tài)改變操作方法。是Vuex修改state的唯一推薦方法,其他修改方式在嚴(yán)格模式下將會報(bào)錯。該方法只能進(jìn)行同步操作,且方法名只能全局唯一。操作之中會有一些hook暴露出來,以進(jìn)行state的監(jiān)控等。
- state:頁面狀態(tài)管理容器對象。集中存儲Vue components中data對象的零散數(shù)據(jù),全局唯一,以進(jìn)行統(tǒng)一的狀態(tài)管理。頁面顯示所需的數(shù)據(jù)從該對象中進(jìn)行讀取,利用Vue的細(xì)粒度數(shù)據(jù)響應(yīng)機(jī)制來進(jìn)行高效的狀態(tài)更新。
- getters:state對象讀取方法。圖中沒有單獨(dú)列出該模塊,應(yīng)該被包含在了render中,Vue Components通過該方法讀取全局state對象。
- Vue組件接收交互行為,調(diào)用dispatch方法觸發(fā)action相關(guān)處理,若頁面狀態(tài)需要改變,則調(diào)用commit方法提交mutation修改state,通過getters獲取到state新值,重新渲染Vue Components,界面隨之更新
單向數(shù)據(jù)流
規(guī)定所有的數(shù)據(jù)操作必須通過 action – mutation – state change 的流程來進(jìn)行,再結(jié)合Vue的數(shù)據(jù)視圖雙向綁定特性來實(shí)現(xiàn)頁面的展示更新

state單一狀態(tài)樹
那么我們?nèi)绾卧?Vue 組件中展示狀態(tài)呢?由于 Vuex 的狀態(tài)存儲是響應(yīng)式的,從 store 實(shí)例中讀取狀態(tài)最簡單的方法就是在計(jì)算屬性中返回某個狀態(tài):
// 創(chuàng)建一個 Counter 組件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
然而,這種模式導(dǎo)致組件依賴全局狀態(tài)單例。在模塊化的構(gòu)建系統(tǒng)中,在每個需要使用 state 的組件中需要頻繁地導(dǎo)入,并且在測試組件時需要模擬狀態(tài)。
Vuex 通過 store 選項(xiàng),提供了一種機(jī)制將狀態(tài)從根組件“注入”到每一個子組件中(需調(diào)用 Vue.use(Vuex)):
const app = new Vue({
el: '#app',
// 把 store 對象提供給 “store” 選項(xiàng),這可以把 store 的實(shí)例注入所有的子組件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div> `
})
通過在根實(shí)例中注冊 store 選項(xiàng),該 store 實(shí)例會注入到根組件下的所有子組件中,且子組件能通過 this.$store 訪問到。讓我們更新下 Counter 的實(shí)現(xiàn):
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
mapState 輔助函數(shù)
當(dāng)一個組件需要獲取多個狀態(tài)時候,將這些狀態(tài)都聲明為計(jì)算屬性會有些重復(fù)和冗余。為了解決這個問題,我們可以使用 mapState 輔助函數(shù)幫助我們生成計(jì)算屬性,讓你少按幾次鍵:
// 在單獨(dú)構(gòu)建的版本中輔助函數(shù)為 Vuex.mapState
import { mapState } from 'vuex'
export default {
computed: mapState({
count: state => state.count,
// 傳字符串參數(shù) 'count' 等同于 `state => state.count`
countAlias: 'count',
// 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
Mutation
更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)。這個回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會接受 state 作為第一個參數(shù):
而且Mutation必須為同步函數(shù)
當(dāng)觸發(fā)一個類型為 increment 的 mutation 時,調(diào)用此函數(shù)?!币獑拘岩粋€ mutation handler,你需要以相應(yīng)的 type 調(diào)用 store.commit 方法:store.commit(‘increment’)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態(tài)
state.count++
}
}
})
Action
Action 類似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接變更狀態(tài)。
Action 可以包含任意異步操作。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Action 函數(shù)接受一個與 store 實(shí)例具有相同方法和屬性的 context 對象,因此你可以調(diào)用 context.commit 提交一個 mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters。
分發(fā) Action
Action 通過 store.dispatch 方法觸發(fā):store.dispatch(‘increment’)
在組件中分發(fā) Action:在組件中使用 this.$store.dispatch(‘xxx’) 分發(fā) action,或者使用 mapActions 輔助函數(shù)將組件的 methods 映射為 store.dispatch 調(diào)用(需要先在根節(jié)點(diǎn)注入 store):
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')`
})
}
}