😎

Vue watchメソッドでオブジェクトの特定プロパティを監視したい

2023/07/21に公開

watchで指定したデータは確かに更新されているのに、なぜか変更として検知せずコールバックも実行してくれない...といったことがあったので備忘録も兼ねてまとめてみました。

オブジェクト型データの特定プロパティを監視対象にしたかった

例えば下記のようなwatchの処理。

<script setup>
import { ref, watch } from 'vue'


const hoge = ref({ name: '' });

// textが更新されるとcallback実行
watch(hoge.name, (newName) => {
    console.log(newName);
});

const changeName = () => {
    hoge.value.name = 'サンプルくん';
};
</script>

<template>
    <button @click="changeName"></button>
</template>

解決方法

hodeというオブジェクト自体はreactiveなデータなので要件には則っているはずなのに...
と思っていましたが、公式ドキュメントにハッキリと書いていました。

Vue公式

以下のようなリアクティブのオブジェクトのプロパティを監視できないことに注意してください:

const obj = reactive({ count: 0 })

// これは、watch() に数値を渡しているので動作しません。
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})

どうやらオブジェクトそのものがリアクティブなデータだとしても、プロパティを取り出した時点で
その取り出したデータ自体はリアクティブな性質を失ってしまうらしい。

解決するには直接データを取り出す以外の方法でwatchにデータを渡す必要がある。

プロパティを返すgetterメソッドを引数に渡す

その特定のプロパティを返すだけの算出プロパティを渡してあげるとか
やろうと思えばいくつか方法はあると思いますが、一番スマート(個人的)なのは
特定のプロパティを返すgetterメソッドをwatchに渡すことかと思う。
というか公式にもそう書いているのでこっちが良さそう。

ちなみにwatchにgetterメソッドを渡した場合、そのメソッドから返却される値に変更が発生した場合にwatchのコールバックを実行する。

// 直接指定してしまっているパターン
watch(hoge.name, (newName) => {
    console.log(newName);
});

// getterで値を返すパターン → 変更を検知する
watch(() => hoge.value.name, (newName) => {
    console.log(newName);
});

終わりに

公式ドキュメント万歳!(詰まったらちゃんとこまめに見る癖つけよう...)

Discussion