🕶️

【Vue.js】props で渡された値の変更を検知したい

2024/03/07に公開

こんにちは!
ラブグラフエンジニアのひろです。

Vue.js にて、 props で渡された値を使ってあれこれしたい時の方法を迷ったので、試したことをまとめます。

やりたかったこと

親コンポーネントで動的に生成され props で渡される値に応じて、子コンポーネントの表示を切り替えたり、子コンポーネント側で値を変えて表示を切り替えたい。

悩んだこと

子コンポーネントで props を直接変更するのは良くない[1]ので、 data で用意したプロパティに代入しようと考えました。

しかし、今回 props で渡される値は親コンポーネントで動的に生成されるので、 created, mounted の時点では undefined になります。

親コンポーネントで値が生成された後に props 経由で受け取ることができる方法、ということで watch, computed などを試してみました。

良さそうな方法

watch を使う。

data() {
  return {
    selectedPrefectureId: null,
  };
},

...

watch: {
  specifiedPrefectureId(newValue) {
    this.selectedPrefectureId = newValue;
  },
},
props: {
  specifiedPrefectureId: {
    required: false,
    type: Number,
  },
},

いくつか試した中でもっともマシに見える方法です。
watch を使って props の変更を検知し、それを data で用意したプロパティに代入しました。

これにより親コンポーネントで specifiedPrefectureId が変われば、子コンポーネントの selectedPrefectureId も変わり、子コンポーネントの表示に反映させることができますし、
子コンポーネント側で selectedPrefectureId を変更して表示を変えることもできるようになりました。

(後者の場合は、親コンポーネントと値がズレるので、値を更新するメソッドを props で受け取っておくなどして、親コンポーネントに変更を反映させる処理も必要になります)

検討した方法それぞれについて書いていきます。

watch

  • 特定のプロパティに変更があった場合だけに絞って検知できる
  • watch の名の通り、値の変更を監視し続けるものなので、変更の検知が1度だけ必要な今回のケースだと少し違和感がある

beforeUpdate

  • DOM更新のたびに毎回呼ばれるので、実質的に props の変更を検知できる
  • 今回のケースだと関係のない値の更新でも無駄に呼ばれてしまう

computed

(今回やりたかったことには合致しませんでしたが)
値を使って何か表示したいだけなら、キャッシュも効いて、値の変更にも対応できる computed が良さそうでした。

以下は computed で props の値を用いて表示に使う例です。
if (specifiedPrefectureId !== undefined) を挟むことで、今回の例のような親コンポーネント側でデータ生成前の状態にも対応できますね。

computed: {
  selectedPrefectureName(specifiedPrefectureId) {
    if (specifiedPrefectureId !== undefined) return "未選択";

    return this.prefectures.find((prefecture) => prefecture.id === specifiedPrefectureId).name;
  }
}

...

props: {
  specifiedPrefectureId: {
    required: false,
    type: Number,
  },
},

終わりに

以上、お読みいただきありがとうございました。

最終的に採用した watch での解決が全方位納得するものではなかったので、他にいい方法が見つかればまた記事にしようと思います。
あまり発生しないケースかもしれませんが、誰かの参考になれば嬉しいです。

脚注
  1. 単方向のデータフロー ↩︎

ラブグラフのエンジニアブログ

Discussion