好在以前接觸過 flux,對於理解 vuex 仍是頗有幫助的。react 學到一半,後來由於太忙,就放棄了,如今也差很少都忘記了。不過感受 vuex 仍是跟 flux 仍是有點區別的。vue
對於不少新手來講,只是閱讀文檔是很差消化,個人建議是看看 vuex 的實例,經過研究實例來學習vuex。這樣就會好理解多了。若是仍是不能理解,最好辦法就是先把store 的四個屬性:state, getters, mutations, actions 記下來,而後再分析四個屬性的特色,什麼地方會用到,是怎樣鏈接在一塊兒的?經過這樣問本身問題來進行學習。react
簡單來講,vuex 就是使用一個 store 對象來包含全部的應用層級狀態,也就是數據的來源。固然若是應用比較龐大,咱們能夠將 store 模塊化,也就是每一個模塊都有本身的 store。分割方式見以下的代碼:vuex
從上面的代碼咱們也能夠看出,一個 store 有四個屬性:state, getters, mutations, actions。下面我將從這四個屬性開始講。數組
先來說state。state 上存放的,說的簡單一些就是變量,也就是所謂的狀態。沒有使用 state 的時候,咱們都是直接在 data 中進行初始化的,可是有了 state 以後,咱們就把 data 上的數據轉移到 state 上去了。當一個組件須要獲取多個狀態時候,將這些狀態都聲明爲計算屬性會有些重複和冗餘。爲了解決這個問題,咱們可使用 mapState
輔助函數幫助咱們生成計算屬性,讓你少按幾回鍵:app
其實就是把 state 上保存的變量轉移到計算屬性上。當映射的計算屬性的名稱與 state 的子節點名稱相同時,咱們也能夠給 mapState
傳一個字符串數組。異步
computed: mapState([ // 映射 this.count 爲 store.state.count 'count' ])
爲了更好地理解這個函數的做用,咱們能夠看看它的源代碼。模塊化
能夠看到,mapstate 便可以接受對象,也能夠接受數組。最終返回的是一個對象。而且 res[key] 的值都是來於 store 裏的,紅色那條代碼就是。這樣就把兩個不相關的屬性鏈接起來了,這也是映射。其餘幾個輔助函數也是相似的。函數
getters上簡單來講就是存放一些公共函數供組件調用。getters 會暴露爲 store.getters
對象,也就是說能夠經過 store.getters[屬性]來進行相應的調用。mapGetters 輔助函數僅僅是將 store 中的 getters 映射到局部計算屬性,其實也就是從 getters 中獲取對應的屬性,跟解構相似。具體以下圖
這樣咱們就能夠將 getters 中的 evenOrOdd 屬性值傳給對應組件中的 evenOrOdd 上。Getters 接受 state 做爲其第一個參數,Getters 也能夠接受其餘 getters 做爲第二個參數。
學習
mutations 與事件相似,更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。因此 mutations 上存放的通常就是咱們要改變 state 的一些方法。this
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變動狀態 state.count++ } } })
咱們不能直接調用一個 mutation handler。這個選項更像是事件註冊:「當觸發一個類型爲 increment
的 mutation 時,調用此函數。」要喚醒一個 mutation handler,你須要以相應的 type 調用 store.commit 方法:
store.commit('increment')
當 mutation 事件類型比較多的時候,咱們可使用常量替代 mutation 事件類型。同時把這些常量放在單獨的文件中可讓咱們的代碼合做者對整個 app 包含的 mutation 一目瞭然:
一條重要的原則就是要記住 mutation 必須是同步函數。
前面說了,mutation 像事件註冊,須要相應的觸發條件。而 Action 就那個管理觸發條件的。
Action 相似於 mutation,不一樣在於:Action 提交的是 mutation,而不是直接變動狀態。Action 能夠包含任意異步操做。
actions: { increment (context) { context.commit('increment') } }
Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit
提交一個 mutation,或者經過 context.state
和 context.getters
來獲取 state 和 getters。
實踐中,咱們會常常會用到 ES2015 的 參數解構 來簡化代碼(特別是咱們須要調用 commit
不少次的時候):
actions: { increment ({ commit }) { commit('increment') } }
還記得咱們前面說過 mutation 像事件類型嗎?所以須要咱們給定某個動做來進行觸發。而這就是分發 action。Action 經過 store.dispatch
方法觸發:
store.dispatch('increment')
此外,咱們還能夠在咱們能夠在 action 內部執行異步操做:
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } }
你在組件中使用 this.$store.dispatch('xxx')
分發 action,或者使用 mapActions
輔助函數將組件的 methods 映射爲 store.dispatch
調用(須要先在根節點注入 store
):
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment' // 映射 this.increment() 爲 this.$store.dispatch('increment') ]), ...mapActions({ add: 'increment' // 映射 this.add() 爲 this.$store.dispatch('increment') }) } }
這句話意思實際上是,當你使用了 mapActions, 你就不須要再次使用 this.$store.dispatch('xxx'),當你沒使用的話,你能夠須要手動去分法。好比下面的代碼:
何時用this.$store.dispatch('xxx'),何時用 mapActions 你們要根據狀況而定的。
最後,問你們一個問題,你知道何時有擴展符 (...) 嗎? 不知道你有沒有注意,有些有擴展符,有些沒有。
提示:有擴展符的,都是被包含在一個對象裏了。