format_list_bulleted
【Vue.js】watchプロパティの書き方・使い方について解説
最終更新日時:2022-06-30 01:58:53



Vueを使っている際に、データの変更を監視して処理する場合があります。そのような場面で便利なVueのwatchプロパティ(監視プロパティ)について解説します。

Vueのwatchプロパティとは?

データの変更を監視して、それをトリガーに非同期処理や複雑な処理を行う必要がある時に使えるのが、watchプロパティ(監視プロパティ)です。watchプロパティを用いればプロパティ名と処理する内容を記述することでこれらを実現してくれます。

Vueのwatchプロパティの使い方

それではwatchプロパティ(監視プロパティ)の書き方について説明していきます。

Vueのwatchプロパティの書き方

watchプロパティでは、監視している変数の変更をトリガーとして次のように書きます。

タイトル:main.js

watch: {
   変更を監視するプロパティ名を記述: function (変更後の値[, 変更前の値]) {
      ここに処理内容を記述
 }
}

またオプションを設定する際には、次のように書きます。(各オプションはデフォルトではfalse)

  • deep(任意) : trueの場合、監視するプロパティがオブジェクトの場合ネストされた値の変更も検知します。「オブジェクトを監視する」で詳しく扱います。
  • immediate(任意) : trueの場合、初期読み込み時にも呼び出します

タイトル:main.js

watch:  {
   変更を監視するプロパティ名を記述: {
     handler: function (変更後の値, 変更前の値) {
       ここに処理内容を記述
   },
     [deep: 真偽値,]
     [immediate: 真偽値,]
 }
}

このようにdeep、immediateのそれぞれをオブジェクトのキーと真偽値で表現し、コールバック関数をhandlerで記述します。

immediateのオプションはpropsを利用する際などに重要になります。propでマウント時に変更を適用することができるので親での値の変化にも対応できるようになります。例えば次のようなコードを想定します。propsについて詳しく知りたい方は「Vueのpropsの書き方・使い方について解説」を参照してみてください!

タイトル:main.js

Vue.component('parent', {
   data: function () {
       return {
           name: "Code-Database"
       }
   },
   template: `
   <div>
   <input type="text" v-model='name'/>
   <child :person=name></child>
   </div>`
})

Vue.component('child', {
   props: ['person'],
   data: function () {
       return {
           greeting: ""
       }
   },
   watch: {
       person: {
           immediate: true,
           handler: function () {
               this.greeting = "hello! " + this.person
           }
       }
   },
   template: '<div>{{ greeting }}</div>'
})

new Vue({
   el: "#sample",
})

immediateがfalseまたは指定なしの場合、初期のコンポーネント読み込み時にはpersonの変更が適用されず、greetingが空文字になります。しかし、immediateをtrueにすることで、まるでcomputedプロパティのように初期の読み込み時からgreetingがhello! Code-Databaseとして読み込まれます。

オブジェクト(Object)を監視する場合

監視する値の対象がオブジェクトである場合、オブジェクトの追加や削除の検出は行われますが、オブジェクト内の各プロパティの値の変更は検出されません。例えば次のようなコードについて考えてみます。

タイトル:main.js

new Vue({
   el: "#sample",
   data: {
       obj: {
           value: ""
       }
   },
   watch: {
       obj: function () {
           //処理を書く
       }
   },
})

このようなプログラムで、valueの値の変更がある際、watchではその変更を検出できません。このような場合は前項にも記載のdeep: trueのオプションを使います。また、オブジェクトの値を個別に書くことでも対応できます。例えば、上記のコードでは次のようにすることで、valueにも監視を適用することができます。

タイトル:main.js

new Vue({
   el: "#sample",
   data: {
       obj: {
           value: ""
       }
   },
   watch: {
       obj.value: function () {
           //処理を書く
       }
   },
})

このようにしてオブジェクトにも対応することができます。

Vueのwatchプロパティの実装例

選択した数字に応じてアドバイスを返してくれるAPIを、非同期で呼び出す場合を考えてみます。その際には次のように監視プロパティを宣言します。

タイトル:index.html

<div id="example">
  <p>
    Choose advice number(1~217):
    <input v-model="answer">
  </p>
  <p>new advice: {{ newAdvice }}</p>
  <p>old advice: {{ oldAdvice }}</p>
</div>

タイトル:vue.html

<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>
var vm = new Vue({
  el: '#example',
  data: {
    oldAdvice: '',
    newAdvice: '',
    answer: ''
  },
  watch: {    // answerの変更に応じて、APIアクセス
    answer: function () {
      this.newAdvice = 'Loading...' // APIの結果が返るまで暫定的に表示
      var vm = this
      var number = this.answer
      axios.get('https://api.adviceslip.com/advice/' + number)
        .then(function (response) {
          vm.newAdvice = response.data.slip.advice + ' ('+ number + ')'
        })
        .catch(function (response) {
          vm.newAdvice = 'Could not get the reponse from the API.'
        })
    },    // newAdviceの変更に応じて、APIアクセス
    newAdvice: function (newData, oldData) {      // newAdviceで表示されたもののうち、アドバイス以外のものを除外
      if(oldData !== 'Loading...' && oldData !== 'Could not get the reponse from the API.'){
        this.oldAdvice = oldData
      }
    }
  },
})
</script>

このように入力欄が変更されるたびにapiへアクセスすることができます。より具体的な処理を次に挙げます。

answerの変更を監視

  • 非同期処理(APIアクセス)
  • APIから結果が返ってくるまでの間は、別の値を表示

 newAdviceの変更を監視

  • newAdviceの元のデータをoldAdviceに代入

watchプロパティとcomputedプロパティの違い

同様のプロパティとしてcomputedプロパティ(算術プロパティ)があります。computedプロパティが使える場合には、簡潔に記述できるためそちらの方が適切です。しかし、上記のように非同期通信のアクセスをするなど、より複雑で汎用的な処理をする場合にはwatchプロパティ(監視プロパティ)が便利です。以下に、watchプロパティを使うべき場合を挙げます。

  • computedプロパティでは処理できない非同期通信などの複雑な処理を行う場合(前項末尾に具体例があります)
  • 更新前と更新後の値を使う場合
  • 処理を実行しても、データは返さない場合

computedプロパティを詳しく勉強したい方は「Vueのcomputedプロパティの書き方・使い方について解説」を参照してみてください!

また、watchプロパティとcomputedプロパティの記述量の比較は次の通りです。

ここでは、firstNumとsecondNumを掛け算した値をresultNumとして表示する場合を考えてみましょう。

watchプロパティの場合

タイトル:app.js

var vm = new Vue({
 el: '#example',
 data: {
   firstNum: 3,
   secondNum: 4,
   resultNum: 12,
 },
 watch: {
   firstNum: function (val) {
     // `this` は vm インスタンスを指します
     this.resultNum = val * this.secondNum;
   },
   secondNum: function (val) {
     this.resultNum = this.firstNum * val;
   }
 }
})

computedプロパティの場合

タイトル:app.js

var vm = new Vue({
  el: '#example',
  data: {
    firstNum:3,
    secondNum:4
  },
  computed: {
    // 算出 getter 関数
   resultNum: function () {
      // `this` は vm インスタンスを指します
      return this.firstNum * this.secondNum
    }
  }
})

このようにcomputedプロパティでの記述の方が、簡潔で可読性の高いコードとなります。そのため、computedプロパティで記述できる場合にはcomputedプロパティを採用することをおすすめします。

この記事のまとめ

本記事ではVueのwatchプロパティ(監視プロパティ)を紹介しました!

  • 最後に記事の要点をまとめてみましょう。
  • データが変更されたことをトリガーに何らかの処理を行いたい際はwatchプロパティを用いる。
  • 処理する内容はwatchプロパティ内にいくつかの記述方法で示す。
  • computedプロパティに比べて記述が冗長だが、非同期や複雑な処理などwatchプロパティでしか実現できないものがある。

Vueのwatchプロパティを是非活用してみましょう!