iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
Modern Web

Vue.js 什麼意思系列 第 19

Day 19:有名模組,無限輔助-Vuex Modules、Map Helper

前兩篇介紹完 Vuex 的核心概念,最後當中大型專案需要組織較為複雜的資料結構時,總不可能一個 index.js 就塞滿所有資料量,這會造成取用和管理上的不便,因此勢必得經過一番模組化,將過於龐大的資料分門別類,同時搭配使用 Map Helpers 來簡化冗長程式碼。

Modules 有名模組

  • 將 Store 分割成多組 module,每個 module 內部各自擁有其自己的 state、getter、mutation、action。

    // member.js
    export default ({
      namespaced: true,
      state: { ... },
      mutations: { ... },
      actions: { ... },
      getters: { ... }
    })
    
    // store/index.js
    import member from './member.js'
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    export default new Vuex.Store({
      modules: {
        member,
    		...
      }
    })
    
  • 在 module 內部設定 namespaced: true,使其成為帶有指定名稱的 module,當 module 被註冊之後,其內部擁有的所有註冊路徑也會跟著調整命名,取用時也能迅速得知模組來源。

    store.state.member.name
    store.getters["member/name"]
    
  • 訪問全域資料:

    • 模組化的 getters 函式,可取用的參數依序為 stategettersrootStaterootGetters

      • 前兩個為模組內的 state 和 getters
      • 後兩個顯示結果相當於 Vuex.Store 實例屬性 store.statestore.getters,差別在於 Vuex.Store 實例屬性為唯讀狀態
      // root.js
      state: {
      	number: 20
      }
      
      // member.js => module name: member
      state: {
      	name: 'John'
      }
      getters: {
      	name: state => state.name,
      }
      
      // test.js => module name: test
      getters: {
      	rootNumber: (state, getters, rootState) => rootState.number,
      	memberName: (state, getters, rootState, rootGetters) => 
              rootGetters['member/name']
      }
      
      console.log(this.$store.getters["test/rootNumber"]) // 20 
      console.log(this.$store.getters["test/memberName"]) // John
      
    • dispatchcommit 的第三個可選參數(options?: Object)若設定為 { root: true },則可跨域取用命名模組的 root actions 或 root mutations。

      // member.js => module name: member
      actions: {
          getName: {...},
      }
      
      // test.js
      actions: {
          getAllData(context): {
              context.dispatch("member/getName", null, { root: true });
      	},
      }
      
    • 註冊為全域 action:在 action 內設定 { root: true },並將 action 函式定義為 handler,便能在全域中使用 dispatch 呼叫該 action。

      // member.js => module name: member
      actions: {
          getMemberName: {
            root: true,
            handler(context, payload) {...},
          },
      }
      
      store.dispatch("member/getMemberName"); // 非全域 action
      store.dispatch("getMemberName"); // 設定 root: true 註冊為全域 action
      

Map Helpers 無限輔助

初學時總會先使用最基本的語法來取用 Vuex 資料:

computed:{
	name(){
		return this.$store.getters["member/name"];
	}
}

然而一旦取用的資料愈來愈多,並且資料皆來自不同的模組時,取用過程便會變成一長串重複又冗長的內容,因此 Map Helpers 正是解決困擾的重要幫手,四個核心概念各有所屬的 Helper 物件——mapStatemapGettersmapMutationsmapActions,透過物件展開運算符(Object Rest/Spread Properties for ECMAScript)簡化程式碼。

首先需將 Helper 引入:

import { mapGetters } from 'vuex'

mapGetters

  1. 陣列寫法:應用於單層結構

    computed: {
      ...mapGetters(['name','age','address','birth', ...])
    }
    
  2. 物件寫法:應用於模組化 Store

    • 可以為 getter 重新命名:

      computed: {
        ...mapGetters({
          memberAge: 'member/age',
          memberName: 'member/name',
        })
      }
      // this.$store.getters["member/name"] 變成 this.memberName
      
    • 相同模組的 getter 可以提取出模組名稱:

      computed: {
        ...mapGetters('member',{
          memberAge: 'age',
          memberName: 'name',
        })
      }
      
      
  3. 物件結合陣列寫法:已提取模組名稱,但無命名需求,則可結合陣列形式更為精簡

    computed: {
      ...mapGetters('member',['age','name'])
    }
    
    

mapMutationsmapActions

在 methods 中使用 mapMutationsmapActions,兩者也都可以帶入 payload 參數。

import { mapMutations, mapActions } from 'vuex';

methods: {
  ...mapMutations({
		books: 'bookList',
		// this.$store.commit('bookList') 變成 this.books()
	})

  ...mapActions(['fetchBookList', 'fetchBook']), 
		// this.$store.dispatch('fetchBookList') 變成 this.fetchBookList()
		// this.$store.dispatch('fetchBook', ISBNId) 變成 this.fetchBook(ISBNId)
}

因為若一律透過 getter 取用 state,基本上就比較少有透過 mapState 取用 state 的機會,因此本篇就先略過介紹了,有興趣的話也可以讀 Vuex 文件「The mapState Helper」了解,用法上應該大同小異。

參考資料


上一篇
Day 18:產地直送,先拿再用-Vuex State、Getters
下一篇
Day 20:全域、路由、元件內-Navigation Guards
系列文
Vue.js 什麼意思30

尚未有邦友留言

立即登入留言