vue 使用vuex來進行元件之間的通訊
緊接著上一篇vue父子元件之間的通訊,當我們的應用遇到多個元件共享狀態時,單向資料流的簡潔性很容易被破壞。
- 多個檢視依賴於同一狀態。
- 來自不同檢視的行為需要變更同一狀態。來自不同檢視的行為需要變更同一狀態。
對於問題一,傳參的方法對於多層巢狀的元件將會非常繁瑣,並且對於兄弟元件間的狀態傳遞無能為力。對於問題二,我們經常會採用父子元件直接引用或者通過事件來變更和同步狀態的多份拷貝。以上的這些模式非常脆弱,通常會導致無法維護的程式碼。
因此,我們為什麼不把元件的共享狀態抽取出來,以一個全域性單例模式管理呢?在這種模式下,我們的元件樹構成了一個巨大的“檢視”,不管在樹的哪個位置,任何元件都能獲取狀態或者觸發行為!
另外,通過定義和隔離狀態管理中的各種概念並強制遵守一定的規則,我們的程式碼將會變得更結構化且易維護。
Vuex
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。Vuex 也整合到 Vue 的官方除錯工具 devtools extension,提供了諸如零配置的 time-travel 除錯、狀態快照匯入匯出等高階除錯功能。
state
Vuex裡的state相當於一個全域性的state,你可以在component的任何地方獲取和修改它。使用 Vuex 並不意味著你需要將所有的狀態放入 Vuex。雖然將所有的狀態放到 Vuex 會使狀態變化更顯式和易除錯,但也會使程式碼變得冗長和不直觀。如果有些狀態嚴格屬於單個元件,最好還是作為元件的區域性狀態。你應該根據你的應用開發需要進行權衡和確定。
//獲取state
this.$store.state.count
//vuex的輔助方法
import { mapState } from 'vuex'
computed:mapState([
'count'
])
getters
Vuex裡的getters類似於computed,有時候我們需要從 store 中的 state 中派生出一些狀態,例如對列表進行過濾並計數,如果有多個元件需要用到此屬性,我們要麼複製這個函式,或者抽取到一個共享函式然後在多處匯入它——無論哪種方式都不是很理想。
Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被快取起來,且只有當它的依賴值發生了改變才會被重新計算。
//直接使用
this.$store.getters.doneTodosCount
//使用輔助方法
import { mapGetters } from 'vuex'
computed:mapGetters({
doneCount: 'doneTodosCount'
})
mutations
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。使用常量替代 mutation 事件型別在各種 Flux 實現中是很常見的模式。這樣可以使 linter 之類的工具發揮作用,同時把這些常量放在單獨的檔案中可以讓你的程式碼合作者對整個 app 包含的 mutation 一目瞭然。用不用常量取決於你——在需要多人協作的大型專案中,這會很有幫助。但如果你不喜歡,你完全可以不這樣做。
一條重要的原則就是要記住 mutation 必須是同步函式,mutation 中的非同步函式中的回撥,當 mutation 觸發的時候,回撥函式還沒有被呼叫,devtools 不知道什麼時候回撥函式實際上被呼叫——實質上任何在回撥函式中進行的狀態的改變都是不可追蹤的。(通常請求和計時器方法都是非同步函式)
//觸發mutations
this.$store.commit('xxx')
//輔助函式
import { mapMutations } from 'vuex'
methods:mapMutations(['increment' ])
actions
對於Action的官方解釋如下。
類似於 mutation,不同在於:
Action 提交的是 mutation,而不是直接變更狀態。
Action 可以包含任意非同步操作。
個人理解如下:
如果有非同步的複雜邏輯並且可以重複呼叫就使用Action。
//觸發action
store.dispatch('increment')
//輔助函式
import { mapActions } from 'vuex'
methods:mapActions(['increment' ])
Module
由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的物件。當應用變得非常複雜時,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 的狀態
store.state.b // -> moduleB 的狀態