前兩篇介紹完 Vuex 的核心概念,最後當中大型專案需要組織較為複雜的資料結構時,總不可能一個 index.js 就塞滿所有資料量,這會造成取用和管理上的不便,因此勢必得經過一番模組化,將過於龐大的資料分門別類,同時搭配使用 Map Helpers 來簡化冗長程式碼。
將 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 函式,可取用的參數依序為 state
、getters
、rootState
、rootGetters
。
store.state
和 store.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
dispatch
和 commit
的第三個可選參數(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
初學時總會先使用最基本的語法來取用 Vuex 資料:
computed:{
name(){
return this.$store.getters["member/name"];
}
}
然而一旦取用的資料愈來愈多,並且資料皆來自不同的模組時,取用過程便會變成一長串重複又冗長的內容,因此 Map Helpers 正是解決困擾的重要幫手,四個核心概念各有所屬的 Helper 物件——mapState
、mapGetters
、mapMutations
、mapActions
,透過物件展開運算符(Object Rest/Spread Properties for ECMAScript)簡化程式碼。
首先需將 Helper 引入:
import { mapGetters } from 'vuex'
mapGetters
陣列寫法:應用於單層結構
computed: {
...mapGetters(['name','age','address','birth', ...])
}
物件寫法:應用於模組化 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',
})
}
物件結合陣列寫法:已提取模組名稱,但無命名需求,則可結合陣列形式更為精簡
computed: {
...mapGetters('member',['age','name'])
}
mapMutations
、mapActions
在 methods 中使用 mapMutations
及 mapActions
,兩者也都可以帶入 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」了解,用法上應該大同小異。