前言

系列文(?)的第二篇,本篇會以參考三的語法表為主軸,文中範例的環境是以 Vue CLI 以上來說明,可參考Vuex_Todo範例幫助理解。

參考

  1. 四張動圖解釋何時該用Redux
  2. Vuex官方文件
  3. Vuex語法表
  4. EventBus

語法(三步驟說明)

  1. 使用第一步,把 Vuex 加進 Vue 的實例裡
// main.js, CLI
import Vue from 'vue'
import Vuex from 'vuex'
import store from './store' // Vuex 實例

Vue.use(Vuex) // 等同於 Vue.prototype.$store = Vuex; 讓所有元件都可藉由 this.$store 使用 vuex

new Vue({
  el: '#app',
  store
})

// with script src, 偶爾在 codepen 上寫寫 Demo 用
// 照順序引入 Vue, Vuex 的 CDN
// 建立 Vuex 實例
var store = new Vuex.Store({
  state: {
    dataList: []
  },
  ...
})

new Vue({
  el: '#app',
  store,
  data: ...,
  computed: {
    dataList() {
      return this.$store.state.dataList;
    },
    ...
  },
  ...
})
  1. 使用第二步,建立 Vuex 實例
// store.js
import Vuex from 'vuex'

new Vuex.Store({
strict: true, // 嚴格限制只能通過 mutation 更改 state, 可在開發時確保資料流, 正式環境應關閉
namespaced: false, // 命名空間的啟用/停用, module 專用, 幫資料和方法取名總有靈感枯竭的狀況, 使用說明參考上方namespaced說明連結
modules: {}, // 載入子層資料, 如 store.js 載入 user.js, user.js 再載入 post.js, 形成 store/user/post的關係
state: {}, // 等同於 Vue 的 data, 放預設資料的地方
getters: {}, // 等同於 Vue 的 computed, 回傳加工過的資料
mutations: {}, // 類似於 Vue 的 methods, 負責更改 state, 只能使用同步操作
actions: {}, // 類似於 Vue 的 methods, 異步(ex:發 API 取資料)會集中在這裡處理,發 commit 到 mutation 更改 state
plugins: [], // 類似於 Vue 的 watch, 初始化時會在 created 後執行一遍, 使用說明參考上方plugins說明連結
devtools: false, // 使 Vue.js devtools 忽略這個 store
})
// vuex 屬性下放的方法有設定一些參數
Vuex.Store({
  state: {
    num: 0,
  },
  mutations: {
    counter(state, payload) {
      state.num += payload; // padload 為可選參數, 不限制型別, 傳遞更改 state 前需要的運算值
    }
  },
  actions: {
    /*
    context 物件解構後包含以下屬性
    {
      state,      // 等同於  store.state, 若在 module 中則為局部 state, 也就是只取得到自己及載入的 module 的資料
      rootState,  // 等同於 store.state, module 專用, 用來取得父層資料
      commit,     // 等同於 store.commit, 要求 mutation 更改資料
      dispatch,   // 等同於 store.dispatch, 觸發其他 action
      getters,    // 等同於 store.getters, 取得 getter 處理過的資料
      rootGetters // 等同於 store.getters, module 專用, 用來取得父層 getters
    }
    */
    calculator(context, payload) {
      // do something ...
      commit('counter', payload); // 要求 counter mutation 更改 state
    }
  },
  getters: {
    /*
    getter 在父層中可傳入兩個參數
    第一是 state, 取得當前 store 的 state
    第二是 getters, 取得其他 getter 輔助計算

    getter 在 module 中可傳入四個參數
    第一是 state, 取得當前 store 的 state
    第二是 getters, 取得其他 getter 輔助計算
    第三是 rootState, 取得父層 state
    第四是 rootGetters, 取得父層 getters 輔助計算
    */
    getNum: (state, getters) => {
      // do something ...
      return state.num;
    }
  }
})
  1. 使用第三步,元件使用 Vuex 方法有二:
// 第一,已使用過 Vue.use(Vuex),可通過 this.$store 使用
export default {
  // ...
  computed: {
    getTodos() {
      return this.$store.getters.doneTodosCount;
    }
    // 因應 Namespace 的使用狀況
    getCounter() {
      return this.$store.moduleName.getters.counterCount;
    }
  }
}
// 第二,使用 Vuex 提供的輔助方法,{ mapState, mapGetters, mapActions, mapMutations }
// mapActions, 把 this.incrementBy(amount) 映射為 this.$store.dispatch('incrementBy', amount)`
// mapMutations, 把 this.incrementBy(amount) 映射為 this.$store.commit('incrementBy', amount)`
// 因應 Namespace 的使用狀況, dispatch 與 commit 可帶第三個參數為 { root: true }, 用途等同於 root 開頭的那幾個, 於 module 中使用
import { mapGetters } from 'vuex'
export default {
  // ...
  computed: {
    ...mapGetters([ // 把 this.firstGetter 映射為 this.$store.getters.firstGetter
      'firstGetter', // 等同於 firstGetter: 'firstGetter'
      anotherGetter: 'secondGetter', // 或是取個比較好懂的名稱
      // ...
    ]),
    // 因應 Namespace 的使用狀況
    ...mapGetters([
      'paraentName/fourthGetter'
    ]),
    ...mapGetters('LevelOne/LevelTwo/LevelThree', [
      'thirdGetter'
    ]),
  }
}

其他

Vuex 還有很多細節是兩篇文章講不完的,麻煩自己到官方文件看,這邊還要介紹一個好用的功能,註冊/卸載 module,用法類似 Vue 的 mixin,重點在於動態、重用,不過記得要在 beforeDestroy 時把 module 和監聽事件一起卸載掉。

// 註冊
store.registerModule('myModule', {
  // ...
})
// with Namespace nested/myModule
store.registerModule(['nested', 'myModule'], {
  // ...
})
// 卸載
store.unregisterModule('myModule')

結語

雖然 Vuex 還在更新,但我不會再更新這篇文章,使用上的觀念不會變。 如果你看到這邊覺得暫時用不到 Vuex,可看參考四的 EventBus,可以不用管這堆麻煩的使用方式,開新檔建立新的 Vue 實例,在需要共用資料的元件引入並共用這個實例的 data、methods…等等,也能暫時解決問題,但資料越多越難管理。