昨天鐵人賽我們kanban專案裡,把column改寫為Vuex狀態管理並透過beforeMount的方式從後端得到資料渲染在網頁上!
看起來好像前進了一大步,但其實Vuex還有很多東西值得研究...(遠目)
例如:
昨天有程式碼裡,眼尖的觀眾應該有發現程式碼截圖中的mapGetters、mapActions還沒有完整說明;
雖然現在可以把Column跟所屬的Ticket資料渲染在頁面上,
但當我們需要更動column的時候(例如第21天介紹的column拖拉功能)如下圖gif顯示:

拖拉完後、新的位置結果也還無法正確存入database,refresh頁面後又回復原來的樣子,並且console會出現錯誤訊息:
[Vue warn] Computed property "columns" was assigned to but it has no setter.
為了解決以上問題~~今天要來介紹幾個可以從Vuex裡面把資料/方法提出來給Vue使用的helper輔助函式!
再次推薦官網影片,
影片裡:這張截圖幫助我清楚理解到Vuex的四個部分:
輔助函式為了讓Vue能夠直接的使用Vuex的資料或方法,這裡把4個helper的對應整理如下:
| Vuex | Vue |
|---|---|
| State | mapState:可取得 state 裡的資料。 |
| Getters | mapGetters:可以把store的getter方法,map到Vue的Computed屬性。 |
| Actions | mapActions 可取得 actions 裡的方法。 |
| Mutations | mapMutations 可取得 mutations 的方法。 |
我們知道有了vuex,不必再煩惱各個元件間如何傳值,而可以很直接地就透過$store來獲取不同的資料
,但是如果vue一次就需要多個vuex中的data的時候....
以一本書book,有書名、作者、價錢為例,我們在Vue裡拿store資料時不需要像醬子寫三遍:
title() { return this.$store.state.title }
author(){ return this.$store.state.author }
price() { return this.$store.state.price }
所以如果Vuex裡有多個state
我們就可以像這樣子:
import {mapState} from 'vuex'
export default {
name: 'book',
computed: mapState(['title','author','price'])
}
helper讓以上原本三句落落長的code等同於mapState(['title','author','price'])。

以上的範例,我們理解到昨天專案裡程式碼中的第一條黃色虛線getters部分:
右側:Vuex的 getters,透過允許傳參數(state)的getters以得到我們想要的值。(相當於vue中的computed屬性)
左側:引入Vuex store的Vue元件,import { mapGetters } from 'vuex';之後,利用mapGetters,把專案裡column的值用map方式get進來。
然後,還記得剛剛一開始的Vue的警告訊息嗎?
[Vue warn] Computed property "columns" was assigned to but it has no setter.
Computed中其實分成兩部分:getter取值和setter給值。
在一般的情況下,computed (只有 getter)來更新資料,如果沒有setter,Computed僅能幫我們觀察data屬性(唯讀),而無法給值;
當computed的屬性要被設值時,就會觸發setter。(例如拖拉column)
因此我們在此範例無法直接使用mapGetter,而是需要在computed內再加一個set(val)的function,並且使用this.$store.commit('UPDATE_COLUMNS', val),去透過Mutations更改值。
computed: {
columns: {
get(){
return this.$store.state.columns
},
set(val){
this.$store.commit('UPDATE_COLUMNS', val)
}
}
},
我們把程式碼再度稍加修改,並且把拖拉Column的methoddragColumn從Vue移到Vuex狀態管理:
在import { mapActions } from 'vuex';之後,
以下程式碼中的黃色虛線部,代表透過mapActions這個helper把Vuex的fetchColumn(網頁一開始渲染column)和dragColumn(拖拉column)這兩個方法引入Vue。

並且在view進入點onlick綁定dragColumn事件
columns/index.html.erb
<div id="column" class="mt-2 px-3" data-kanbanid="<%= @kanban.id%>" >
<!-- 綁定v-model: 拖完之後,資料也跟著改變位置 -->
<draggable v-model="columns" class="flex" @change="dragColumn">
<Column v-for="column in columns" :column="column" :key="column.id"></Column>
</draggable>
</div>
雖然在本日鐵人賽還沒用到mapMutation,
不過還是來舉個例子介紹一下:
跟之前的mapState等語法類似,
Vue的mapMutations也是簡寫,把Mutation的方法map進Vue裡:
methods:{
...mapMutations(['GET_SALARY','GET_BONUS'])
}
以上會等同於:
getSalary(payLoad){
this.$store.commit('GET_SALARY',payLoad)
}
getBonus(payLoad){
this.$store.commit('GET_BONUS',payLoad)
}
是不是節省了很多行重複的程式碼呀?
payLoad參數可以在調用方法的時候時寫入。
<button @click="getSalary({ money: 40000 })">領薪水摟!</button>
<button @click="getBonus({ money: 60000 })">發年終獎金!</button>
Actions和Mutation的差別:
呼~~Vuex狀態管理真是一門大學問!
最後來一張dragColumnmethod改成Vuex後,devtool中每一條mutation前後狀態的快照,做為今天的ending:)
Ref: