Vuexのstore(ストア)を使うと、各コンポーネント間で個別にデータのやり取りすることなく、データを一元的に管理できます。Vueでは欠かせない機能といえるでしょう。
state(変数、コンポーネントでのプロパティにあたる)の状態変化を監視して、任意のactionなどを実行する、といった使い方もします。
今回はstoreの状態監視をするとき、複数のstateを同じwatchハンドラで監視する方法を紹介します。主な対象はVue2です。
実行環境
vue@2.6.12
何がしたいか
以下のような state があるとします。
state: {
userDataAlpha: false,
userDataBeta: true,
}
watchハンドラでそれぞれのstateの状態変化を監視し、同じ関数を実行したいとき、個別のwatchに登録しようとすると以下のように書けます。
mounted() {
this.$store.watch(
(state, getters) => getters.getUserDataAlpha,
(newVal, oldVal) => {
console.log(`Updated ${oldVal} to ${newVal}`);
},
)
this.$store.watch(
(state, getters) => getters.getUserDataBeta,
(newVal, oldVal) => {
console.log(`Updated ${oldVal} to ${newVal}`);
},
)
},
このときuserDataAlphaを変化させると、コンソールには以下のように出力されます。
Updated true to false
Updated false to true
しかし上記のようにすると、同じ内容を書くことになり冗長です。
できればやりたくありません。
そこで以下のようなテクニックで書き直します。
Vuexのstateを一つのwatchハンドラで監視する
方法1. 配列にまとめて deep:true を指定
stateを以下のように連想配列の形に変更します。
state: {
userData: {
userDataAlpha: true,
userDataBeta: true,
}
},
こうすれば userDataの中身がひとつでも変化すればwatchがキャッチしてくれます。
watch()にdeep:trueパラメータを渡します。
mounted() {
this.$store.watch(
(state, getters) => getters.getUserData,
(newVal) => {
console.log(`${newVal.userDataAlpha}, ${newVal.userDataBeta}`);
},
{ deep: true }
)
},
userDataAlphaを変化させると、コンソールには以下のように出力されるはずです。
false, true
true, true
方法2. トリックを使う
コンポーネントのcomputed プロパティにて、あらかじめstateをひとつに結合しておき、それを監視する方法です。
computed: {
...mapState(["userDataAlpha", "userDataBeta"]),
userDatasCombined() {
return `${this.userDataAlpha},${this.userDataBeta}`;
},
},
userDatasCombinedを用意しておき、それをコンポーネントのwatch()に登録します。
watch: {
userDatasCombined(newVal, oldVal) {
console.log(`Updated (${oldVal}) to (${newVal})`);
}
}
userDataAlphaを変化させると、コンソールには以下のように出力されるはずです。
Updated (true,true) to (false,true)
Updated (false,true) to (true,true)