1. 程式人生 > >談談我對vuex的理解

談談我對vuex的理解

在近期做得專案中,用到Vue框架,必不可少的也用到vuex狀態管理,再加上面試中也被問到了,索性把這一塊拿出來抽時間整理一下:

核心概念

Vuex 是適用於 Vue.js 應用的狀態管理庫,為應用中的所有元件提供集中式的狀態儲存與操作,保證了所有狀態以可預測的方式進行修改。
官網的一張圖:
vuex

  • Vue Components:Vue元件。HTML頁面上,負責接收使用者操作等互動行為,執行dispatch方法觸發對應action進行迴應。
  • dispatch:操作行為觸發方法,是唯一能執行action的方法。
  • actions:操作行為處理模組。負責處理Vue Components接收到的所有互動行為。包含同步/非同步操作,支援多個同名方法,按照註冊的順序依次觸發。向後臺API請求的操作就在這個模組中進行,包括觸發其他action以及提交mutation的操作。該模組提供了Promise的封裝,以支援action的鏈式觸發。
  • commit:狀態改變提交操作方法。對mutation進行提交,是唯一能執行mutation的方法。
  • mutations:狀態改變操作方法。是Vuex修改state的唯一推薦方法,其他修改方式在嚴格模式下將會報錯。該方法只能進行同步操作,且方法名只能全域性唯一。操作之中會有一些hook暴露出來,以進行state的監控等。
  • state:頁面狀態管理容器物件。集中儲存Vue components中data物件的零散資料,全域性唯一,以進行統一的狀態管理。頁面顯示所需的資料從該物件中進行讀取,利用Vue的細粒度資料響應機制來進行高效的狀態更新。
    • getters:state物件讀取方法。圖中沒有單獨列出該模組,應該被包含在了render中,Vue Components通過該方法讀取全域性state物件。

Vue元件接收互動行為,呼叫dispatch方法觸發action相關處理,若頁面狀態需要改變,則呼叫commit方法提交mutation修改state,通過getters獲取到state新值,重新渲染Vue Components,介面隨之更新

完整流程 單向資料流

規定所有的資料操作必須通過 action – mutation – state change 的流程來進行,再結合Vue的資料檢視雙向繫結特性來實現頁面的展示更新
這裡寫圖片描述

state單一狀態樹

那麼我們如何在 Vue 元件中展示狀態呢?由於 Vuex 的狀態儲存是響應式的,從 store 例項中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:

// 建立一個 Counter 元件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}

然而,這種模式導致元件依賴全域性狀態單例。在模組化的構建系統中,在每個需要使用 state 的元件中需要頻繁地匯入,並且在測試元件時需要模擬狀態。
Vuex 通過 store 選項,提供了一種機制將狀態從根元件“注入”到每一個子元件中(需呼叫 Vue.use(Vuex)):

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
    }
  }
}

mapState 輔助函式
當一個元件需要獲取多個狀態時候,將這些狀態都宣告為計算屬性會有些重複和冗餘。為了解決這個問題,我們可以使用 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
    }
  })
}

Mutation

更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字串的 事件型別 (type) 和 一個 回撥函式 (handler)。這個回撥函式就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個引數:
而且Mutation必須為同步函式
當觸發一個型別為 increment 的 mutation 時,呼叫此函式。”要喚醒一個 mutation handler,你需要以相應的 type 呼叫 store.commit 方法:store.commit(‘increment’)

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態
      state.count++
    }
  }
})

Action

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

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 函式接受一個與 store 例項具有相同方法和屬性的 context 物件,因此你可以呼叫 context.commit 提交一個 mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters。

分發 Action

Action 通過 store.dispatch 方法觸發:store.dispatch(‘increment’)
在元件中分發 Action:在元件中使用 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` 也支援載荷:
  'incrementBy' // 將 `this.incrementBy(amount)` 對映為 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
  add: 'increment' // 將 `this.add()` 對映為 `this.$store.dispatch('increment')`
})

}
}