//本文主要參考vuex官方文檔做的總結
vuex是vue的狀態管理模式,主要可以解決父子組件嵌套層數較多,或者兄弟組件之間需要維護同一個狀態的情況。
vuex的核心是"store",簡單的store如下:
// 如果在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
可以通過 store.state
來獲取狀態對象,以及通過 store.commit
方法觸發狀態變更:
store.commit('increment') console.log(store.state.count) // -> 1
通過store選項將狀態從根組件『注入』到每一個子組件中:
const app = new Vue({ el: '#app', // 把 store 對象提供給 “store” 選項,這可以把 store 的實例注入所有的子組件 store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` })
通過在根實例中注冊 store
選項,該 store 實例會注入到根組件下的所有子組件中,且子組件能通過 this.$store
訪問到。讓我們更新下 Counter
的實現:
const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } }
值得注意的是我們這里需要在computed計算屬性里面去獲取這個count,而當一個組件需要獲取的狀態比較多的時候都聲明為計算屬性就會顯得比較冗余,因此可以引入mapstate這個輔助函數:
// 在單獨構建的版本中輔助函數為 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: { ...mapState({ // 箭頭函數可使代碼更簡練 count: state => state.count, // 傳字符串參數 'count' 等同於 `state => state.count` countAlias: 'count', // 為了能夠使用 `this` 獲取局部狀態,必須使用常規函數 countPlusLocalState (state) { return state.count + this.localCount } }) } }
以上代碼等同於:
import { mapState } from 'vuex' export default { computed: { count() { return this.$store.state.count }, countAlias() { return this.$store.state['count'] }, countPlusLocalState() { return this.$store.state.count + this.localCount } } }
當映射的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState
傳一個字符串數組:
computed: mapState([ // 映射 this.count 為 store.state.count 'count' ])
有時候我們需要從 store 中的 state 中派生出一些狀態,Vuex 允許我們在 store 中定義『getters』(可以認為是 store 的計算屬性)。Getters 接受 state 作為其第一個參數,也可以接受getter作為第二個參數:
const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } })
Getters 會暴露為 store.getters
對象:
store.getters.doneTodos
我們可以很容易地在任何組件中使用它:
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }
就像映射state一樣,getters也可以通過mapGetters進行映射:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用對象展開運算符將 getters 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
以上介紹的是怎么獲取狀態,那么如何修改狀態?Vuex 中的 mutations 非常類似於事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個參數:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變更狀態 state.count++ } } })
這里increment稱為type,調用的函數稱為handler,要喚醒一個 mutation handler,你需要以相應的 type 調用 store.commit 方法:
store.commit('increment')
你可以在組件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
輔助函數將組件中的 methods 映射為 store.commit
調用:
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment' // 映射 this.increment() 為 this.$store.commit('increment') ]), ...mapMutations({ add: 'increment' // 映射 this.add() 為 this.$store.commit('increment') }) } }
需要注意的是mutation 必須是同步函數。那么如何進行異步操作,此時可以通過action。與mutation的區別在於:
- Action 提交的是 mutation,而不是直接變更狀態。
- Action 可以包含任意異步操作。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
也可以通過參數解構:
actions: { increment ({ commit }) { commit('increment') } }
Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,因此你可以調用 context.commit
提交一個 mutation,或者通過 context.state
和 context.getters
來獲取 state 和 getters。
Action 通過 store.dispatch
方法觸發:
store.dispatch('increment')
同樣的,action也可以映射:
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment' // 映射 this.increment() 為 this.$store.dispatch('increment') ]), ...mapActions({ add: 'increment' // 映射 this.add() 為 this.$store.dispatch('increment') }) } }
Vuex 允許我們將 store 分割到模塊(module)。每個模塊擁有自己的 state、mutation、action、getters、甚至是嵌套子模塊——從上至下進行類似的分割:
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 的狀態