初見狀態管理工具 Vuex (2) State、Getters


Posted by Calon on 2022-04-26

※本文章主要以 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 指南》

#vuex #Vue.js







Related Posts

[FE201] 前端中階:jQuery

[FE201] 前端中階:jQuery

讓你好像很厲害的Command Line

讓你好像很厲害的Command Line

Day01 : 數字、字串、變數

Day01 : 數字、字串、變數


Comments