Vuex 學習總結


好在之前接觸過 flux,對於理解 vuex 還是很有幫助的。react 學到一半,后來因為太忙,就放棄了,現在也差不多都忘記了。不過感覺 vuex 還是跟 flux 還是有點區別的。

 

對於很多新手來說,只是閱讀文檔是不好消化,我的建議是看看 vuex 的實例,通過研究實例來學習vuex。這樣就會好理解多了。如果還是不能理解,最好辦法就是先把store 的四個屬性:state, getters, mutations, actions 記下來,然后再分析四個屬性的特點,什么地方會用到,是怎樣連接在一起的?通過這樣問自己問題來進行學習。

 

簡單來說,vuex 就是使用一個 store 對象來包含所有的應用層級狀態,也就是數據的來源。當然如果應用比較龐大,我們可以將 store 模塊化,也就是每個模塊都有自己的 store。分割方式見如下的代碼:

從上面的代碼我們也可以看出,一個 store 有四個屬性:state, getters, mutations, actions。下面我將從這四個屬性開始講。

 

1、State

先來講state。state 上存放的,說的簡單一些就是變量,也就是所謂的狀態。沒有使用 state 的時候,我們都是直接在 data 中進行初始化的,但是有了 state 之后,我們就把 data 上的數據轉移到 state 上去了。當一個組件需要獲取多個狀態時候,將這些狀態都聲明為計算屬性會有些重復和冗余。為了解決這個問題,我們可以使用 mapState 輔助函數幫助我們生成計算屬性,讓你少按幾次鍵:

其實就是把 state 上保存的變量轉移到計算屬性上。當映射的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字符串數組。

computed: mapState([
  // 映射 this.count 為 store.state.count
  'count'
])

 為了更好地理解這個函數的作用,我們可以看看它的源代碼。

可以看到,mapstate 即可以接受對象,也可以接受數組。最終返回的是一個對象。並且 res[key] 的值都是來於 store 里的,紅色那條代碼就是。這樣就把兩個不相關的屬性連接起來了,這也是映射。其他幾個輔助函數也是類似的。

 

2、Getters

getters上簡單來說就是存放一些公共函數供組件調用。getters 會暴露為 store.getters 對象,也就是說可以通過 store.getters[屬性]來進行相應的調用。mapGetters 輔助函數僅僅是將 store 中的 getters 映射到局部計算屬性,其實也就是從 getters 中獲取對應的屬性,跟解構類似。具體如下圖 
這樣我們就可以將 getters 中的 evenOrOdd 屬性值傳給對應組件中的 evenOrOdd 上。Getters 接受 state 作為其第一個參數,Getters 也可以接受其他 getters 作為第二個參數。

3、Mutations

mutations 與事件類似,更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。所以 mutations 上存放的一般就是我們要改變 state 的一些方法。

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 必須是同步函數

4、Actions

前面說了,mutation 像事件注冊,需要相應的觸發條件。而 Action 就那個管理觸發條件的。

Action 類似於 mutation,不同在於:Action 提交的是 mutation,而不是直接變更狀態。Action 可以包含任意異步操作。 

actions: {
    increment (context) {
      context.commit('increment')
    }
  }

 

Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,因此你可以調用 context.commit 提交一個 mutation,或者通過 context.statecontext.getters 來獲取 state 和 getters。
實踐中,我們會經常會用到 ES2015 的 參數解構 來簡化代碼(特別是我們需要調用 commit 很多次的時候):

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

 

還記得我們前面說過 mutation 像事件類型嗎?因此需要我們給定某個動作來進行觸發。而這就是分發 action。Action 通過 store.dispatch方法觸發,dispatch 里面的是 actions 中的函數的名字:

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 大家要根據情況而定的。

 

 

最后,問大家一個問題,你知道什么時候有擴展符 (...) 嗎? 不知道你有沒有注意,有些有擴展符,有些沒有。

 

提示:有擴展符的,都是被包含在一個對象里了。

還有就是在有多個 store 的時候,注意即使是在不同 store 里, actions 里面的函數名字也是不能存在相同的,否則就是相當於那個函數調用兩遍。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM