[Vue] Vuex 是什麼? 怎麼用? — Modules (4/5)
全系列共五篇:
一、[Vue] Vuex 是什麼? 怎麼用? — State、Mutations (1/5)
二、[Vue] Vuex 是什麼? 怎麼用? — Actions (2/5)
三、[Vue] Vuex 是什麼? 怎麼用? — Getters (3/5)
四、[Vue] Vuex 是什麼? 怎麼用? — Modules (4/5)
五、[Vue] Vuex 是什麼? 怎麼用? — 統整、專案結構(5/5)
Outline:
1. Why Modules
2. Usage
Why Modules
如果專案規模比較龐大,store 裡面的 state 可能會變得越來越肥,可能會有會員資訊、訂單資訊、商品資訊、最新消息…等,所以 Vuex 允許我們使用 Modules 來解決這個問題,將 store 中各類的 state 分類管理。
Usage
Module — State
原本的 state 已經超級肥:
把這些不同分類的 state 拆成物件分出去,各自的 state 也可以擁有自己的 state, action, getters…等,並在 new Vuex 的時候註冊他們:
在 component 取用 modules 的 state :
Module — Mutations
mutations 一樣是吃 state, payload
兩個參數:
const moduleUser = {
state: {
name: "emma",
age: 18
},
mutations: {
chageAge(state, payload) {
state.age++;
}
},
}
這邊的 state.age 代表 moduleUser 自己的 state
Module — Getters
Module 裡面的 Getters 會有這些參數:state, getters, rootState, rootGetters
,前面的 state, getters
一樣是 module 自己的 state 跟 getters,rootState, rootGetters
則表示回到根部 (new Vuex.Store 那一層),舉例:
app.vue:
在 template 使用 module user 的 getters,讓 getters 拿到自己的 state、另一個 module 的 state,和根部的 state
這邊直接 import 了 mapGetters 用,如果不知道 mapGetters 是什麼可以參考我的第三篇:[Vue] Vuex 是什麼? 怎麼用? — Getters (3/5)
store.js
這邊要注意一個小地方,在 moduleUser 裡面的 getters 這邊,假設如範例我要使用 rootState
這個參數,前面兩個 state, getters
也要帶上去,如果只寫 rootState
就會被當成自己的 state,他是依序判斷參數的
就是醬子,不小心透露我本人 20 歲(開玩笑的不要檢舉我)
Module — Actions
actions 在第二篇說明 actions 的時候有提到他可以帶入的參數,context 原本有 commit, dispatch, state, getters
,在 modules 裡面,和 getters 一樣也有 rootState, rootGetters
可以用
區域、全域、namespaced
使用了 module 之後,module 們的 actions, mutations, getters 都是全域共用的,全域共用是什麼意思呢?意思就是如果 moduleA 和 moduleB 都有一個 actions 叫做 sayHi
,那麼我在 component dispatch sayHi
的話,兩個 module 的 sayHi
都會執行,下面用範例來看看:
複習一下:
commit 拿來呼叫 mutations,dispatch 拿來呼叫 actions
actions 拿來呼叫 mutations,只有 mutations 可以更動 state
先在 store.js 中將兩個 module 新增一個一樣名字的 actions sayHi
:
接著在 app.vue 的 template 中,在 mounted 的時候 dispatch sayHi
這個 actions:
mounted() {
this.$store.dispatch("sayHi");
},
就會看到 console 中的確跑出了兩句,真的兩個 module 的 actions 都執行了
為了避免這樣的狀況發生,除了把名稱都設定成不一樣的,可以在 module 裡面加上一個設定:
namespaced: true
以剛剛的兩個 Hello 來看,我們把兩個 module 都加上這個設定:
加上了 namespaced 這個設定之後,在 component 要 dispatch 這個 actions 前面就要加上 module 的名稱:
mounted() {
this.$store.dispatch("user/sayHi");
this.$store.dispatch("another/sayHi");
},
上面的 age getters 範例也是一樣的道理,我們剛剛用 mapGetters 呼叫了 moduleUser 的 getters,不用指定是哪個 module 的 getters,他就成功執行了,就是因為 getters 是全域共用的,現在 module 自己已經加上了 namespaced 這個設定,getters 也要加上才能成功使用:
...mapGetters({
GetAge: "user/GetAge",
GetRealAge: "user/GetRealAge",
GetNextAge: "user/GetNextAge"
})
這裡把剛剛 mapGetters 用法從陣列轉為物件了,因為原本陣列的用法,template 上的名字需要和 getters 一樣,現在因為 namespaced 的關係,getters 的名字前面需要加上 module 的名字,所以就改用物件把 template 的 getters 名稱指定到 module 的 getters。
在 modules 之間 actions 或 mutations 互相呼叫也一樣,但是有一個設定要加,原本在 module 加上 namespaced 之前,如果 moduleA 的 actions 要呼叫 moduleB 的 mutations,會是這樣:
因為 module 們的 actions, mutations, getters 都是全域共用的,所以我在 moduleAnother 的 actions addYear
commit 呼叫 moduleUser 的 mutations addAge
直接呼叫就會呼叫得到了
如果已經忘了 actions 來這邊複習:[Vue] Vuex 是什麼? 怎麼用? — Actions (2/5)
在 template 這邊加上一個 button,:
這樣在點擊 button 的時候,上面的 age 就會跟著變動了
那麼加上 namespaced 之後要怎麼寫呢?
先把 template 上的 methods 加上 model name:
methods: {
add() {
this.$store.dispatch("another/addYear");
}
}
接下來在 store.js 中,在 moduleAnother 的 actions addYear
commit 會帶上三個參數:mutations, payload, {root:true}
:
commit('user/addAge', 2, { root: true })
第一個參數一樣是要呼叫的別的 module 的 mutations,第二個參數則為 payload,如果不需要 payload,也可以寫 null
就好,第三個 { root: true }
表示為根部,就是從底部找的意思,開啟 namespaced 後,module 之間的 actions, getters, mutations 之間要互相呼叫都要記得加上{ root: true }
,如果沒有加上這句話,vuex 會當作你還是要呼叫自己的東西,就會錯了
Module — 使用 mapState, mapMutations, mapActions, mapGetters
以上述的範例來看,假設我有多個 state,使用 mapState,也在 namespaced 開啟的狀況下,會變成像是:
/app.vue
/store.js
在 component 中,如果有很多個 state 要指定,所以也可以將
...mapState({
MyName: state => state.user.name,
gender: state => state.user.gender,
addr: state => state.user.addr
}),
改寫為:
...mapState("user", {
MyName: state => state.name,
gender: state => state.gender,
addr: state => state.addr
}),
在 maptState 前面加入一個 module 名的字串,就可以指定要找的 module 名稱了。
如果 template 上的名稱跟 state 裡面的名稱一樣,改為陣列的話,會更簡短:
...mapState("user", ["name", "gender", "addr"]),
module 的 mapMutations、mapGetters、mapActions 也都是一樣的,
把剛剛的 mapGetters 再拿回來看一次:
...mapGetters({
GetAge: "user/GetAge",
GetRealAge: "user/GetRealAge",
GetNextAge: "user/GetNextAge"
})
可以改成:
...mapGetters("user", ["GetAge", "GetRealAge", "GetNextAge"])
或是再更精簡一點:
這樣在這邊的 mapState 和 mapGetters 就會直接去 user 這個 module 裡面找了。
Module 的用法差不多就說明到這邊,講了很多,下一篇再把前面的重點整理下 🏃🏃🏃
內容若有任何錯誤,歡迎留言交流指教! 🐬全系列共五篇:
一、[Vue] Vuex 是什麼? 怎麼用? — State、Mutations (1/5)
二、[Vue] Vuex 是什麼? 怎麼用? — Actions (2/5)
三、[Vue] Vuex 是什麼? 怎麼用? — Getters (3/5)
四、[Vue] Vuex 是什麼? 怎麼用? — Modules (4/5)
五、[Vue] Vuex 是什麼? 怎麼用? — 統整、專案結構(5/5)