※本文章主要以 Vue CLI 中的寫法為主。
State 共用狀態
state 有點像是元件中的 data。
我們可以從元件之間會共用的 data 資料放到 state 去集中管理,這邊將一個表達飢餓狀態的 isHungry 放進來:
export default createStore({
state: {
isHungry: false,
},
});
這時我們到元件取出 state,因為是 state 是響應式狀態,也就是資料變化,所以使用 computed 觀察來自 store 的資料:
<template>
我很餓:{{ isHungry }}
</template>
<script>
export default {
computed: {
isHungry() {
return this.$store.state.isHungry;
},
},
};
</script>
我們可以看到畫面上呈現「我很餓:false」的文字。
這時我們再在 state 裡面多添加一些資料:
export default createStore({
state: {
isHungry: false,
hungerIndex: 0,
food: 'french fries',
},
});
之後,我們再到元件去將這些資料用 computed 取出,但要將 3 筆資料一個個打出來有點麻煩,而且當資料筆數太多,一個個輸入不就很花時間嗎?
這時我們可以用 mapState
來幫我們。
首先要記得在元件內從 Vuex 裡面 import mapState:
import { mapState } from 'vuex';
接下來只要在 mapState 裡面傳入跟 state 的鍵值一樣的字串陣列:
<script>
export default {
computed: mapState([
'isHungry',
'hungerIndex',
'food',
]),
};
</script>
這樣 mapState 就會回傳一個物件,而物件內容是我們剛才手動輸入的 computed。
當然我們也可以傳入物件當作參數,而用物件的好處是可以自訂在這個元件下想要的 key,並且也可以使用 function 的方式:
<script>
export default {
computed: mapState({
hungerStatus: 'isHungry',
hungerIndex: state => state.hungerIndex, // 這裡透過 state 參數來取得 store 的資料,所以不需要使用 this
}),
};
</script>
但這時你會發現 mapState 直接佔用了 computed,但我的元件裡面有其他的資料需要使用 computed 來計算怎麼辦?
剛才我們提到 mapState 會回傳一個 computed 物件,所以我們只要用 ES 6 的物件展開來加入 computed 內即可。
<script>
export default {
computed: {
...mapState({
hungerStatus: 'isHungry',
hungerIndex: state => state.hungerIndex,
}),
},
};
</script>
Getters
getters 如上一篇有介紹過的,它像是 store 中的 computed。
我們來透過舉例來了解 getters 的用法,state 沿用上面的:
export default createStore({
state: {
isHungry: false,
hungerIndex: 0,
food: 'french fries',
},
});
假設我希望在一段時間內將飢餓指數在一開始就是 20 了,我們可以直接在元件使用 computed 來計算:
<script>
export default {
computed: {
hungerIndex() {
return this.$store.state.hungerIndex += 20;
},
},
};
</script>
但是這個作法只會在此元件裡面顯示更新後的狀態,其他元件的飢餓指數預設還是原本的 0,這時我們可以將這一段邏輯寫到 getters 裡:
export default createStore({
state: {
isHungry: false,
hungerIndex: 0,
food: 'french fries',
},
getters: {
higherHungerIndex(state) {
return state.hungerIndex + 20;
},
},
});
接下來跟取得 state 時一樣用 computed 來取得:
export default {
computed: {
higherHungerIndex() {
// 注意:這裡是要取 getters
return this.$store.getters.higherHungerIndex;
},
},
};
另外,我們可以在 getters 裡面取得另一個 getters,例如當飢餓指數超過 50 的時候顯示 '我很餓':
export default createStore({
state: {
isHungry: false,
hungerIndex: 0,
food: 'french fries',
},
getters: {
higherHungerIndex(state) {
return state.hungerIndex + 20;
},
showHungryStatus(state, getters) {
return getters.higherHungerIndex >= 50 ? '我很餓' : '還不餓';
},
},
});
像這樣只要帶入第二個參數 getters 就可以調用其他 getters 的資料,當 higherHungerIndex 有變化的時候,showHungryStatus 就會跟著改變。
最後,getters 也有像 mapState 一樣的方法——mapGetters 讓我們在取得多個 getters 資料時更方便,一樣在使用前要先 import mapGetters:
import { mapGetters } from 'vuex';
export default {
computed: mapGetters([
'higherHungerIndex',
'showHungryStatus',
]),
};
其他取得方式與 mapState 一樣。
參考資料
- Vuex 官方文件
- 許國政(Kuro),《重新認識 Vue.js:008 天絕對看不完的 Vue.js 3 指南》