【Vue.js 】 watch データの変更を監視

# はじめに
watchは特定のデータや算出プロパティの状態の変化を監視して、変化があったときに登録した処理を実行するプロパティ。
データや算出プロパティの変更が処理のトリガー（きっかけ）となる。


## 使い方
watchオプションに```監視するデータの名前```と```変化した時に呼び出されるハンドラ（関数）```を定義する。
データの比較が必要な場合は、第1引数として```新しい値```、第2引数として```古い値```が受け取れる。
※ここではインスタンスが生成されると同時にwatchが呼び出されている。

**基本的な書き方**

```sample.js
new Vue({
  watch: {
    監視するデータ: function(新しい値, 古い値) {
      // データが変化した時に行いたい処理
    },
    // ↓ オブジェクトのプロパティも監視できる
    'item.value': function(新しい値, 古い値) {
      // 処理
    }
  }
})
```
↓ データ等を入れて記述してみる

```sample.js
new Vue({
  el: 'app',
  data: {
    flag: true
  },
  methods: {
    changeFlag: function() {
      this.flag = !this.flag
    }
  },
  // データflagをwatchオプションに定義
  watch: {
    flag: function(newVal, oldVal) {
      // データの値が変化した時にコンソールに新しい値と古い値を出力
      console.log(newVal, oldVal)
    }
  }
});
```

## watchのオプション
下記のオプションを任意で設定できる（デフォルトではfalse）

| プロパティ          |       値          |         説明                   |
|:-----------------|:-----------------:|:-------------------|
| deep             |       Boolean     |ネストされたオブジェクトも監視する       |
| immediate        |       Boolean     |初期読み込み時にも呼び出す           |

オプションを使用する際はオブジェクトにまとめ、```handler```プロパティにハンドラを定義する。

```sample.js
new Vue({
  el: 'app',
  data: {
    list: [
      { name: '鉛筆', price: 98 },
      { name: '消しゴム', price: 100 }
  ]
  },
  watch: {
    // listもしくはlist内のプロパティに変更があった場合に処理が実行される
    list: {
      handler: function(newVal, oldVal) {
        console.log(newVal)
      },
      // deepがfalseだとオブジェクト内の値が変更されても処理が実行されない
      deep : true,
      immediate: true
    }
  }
});
```

## watchオプションとcomputedオプションの違い
同じようなプロパティとしてデータ変更時にのみ処理を実行するcomputedオプションがある。
→ [computedオプションについてこちら](https://qiita.com/smkhkc/items/b564c03222b5f9f23cfb#-computed%E7%AE%97%E5%87%BA%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3)

まずはwatchプロパティとcomputedプロパティで同じ処理を記述して比較してみる。
↓ firstNum と secondNum を掛けてresultNumを表示する

```sample.js
// watchの場合
new Vue({
  el: 'app',
  data: {
    firstNum: 2,
    secondNum: 3,
    resultNum: 6
  },
  watch: {
    firstNum: function(newVal) {
      this.resultNum = newVal * this.secondNum;
    },
    secondNum: function(newVal) {
      this.resultNum = this.secondNum * newVal;
    },
  }

})
```

```sample.js
// computedの場合
new Vue({
  el: 'app',
  data: {
    firstNum: 2,
    secondNum: 3
  },
  computed: {
    resultNum: function() {
      return this.firstNum * secondNum;
    }
  }

})
```

このようにcomputedオプションの方が簡潔で可読性の高いコードが記述できる。そのため、computedオプションで記述できる場合はcomputedオプションを使用するのが望ましい。

watchオプションは下記のような場面で使う。

◎ 非同期通信（APIアクセス）などの複雑な処理を行う場合
　（computedオプションでは処理できない）
◎ 更新前と更新後の値を使う場合
◎ 処理を実行してもデータを返さない場合

## メソッド内でwatchを登録
インスタンスメソッドとして```this.$watch```と定義することでメソッド内でもwatchが登録できる。
今までの書き方とは少し異なり、下記のように引数を渡してあげる。

```sample.js
// 書き方
this.$watch('監視したいデータ',ハンドラ（関数）,オプション)

// ライフサイクルのcreatedにwatchを登録してみる
created() {
  this.$watch('value', function(newVal, oldVal) {
    // 処理
  }, {
    deep: true,
    immediate: true
  })
}
```

### 監視の解除
返り値を使って監視を解除することができる。

```sample.js
var unwatch = this.$watch('value' function() {})

unwatch()
```
#### 一度だけ監視
一度しか監視しないwatchを```unwatch()```を使って登録する。

```sample.js
new Vue({
  el: 'app',
  data: {
    edited: false,
    list: [
      { name: '鉛筆', price: 98 },
      { name: '消しゴム', price: 100 }
    ]
  },
  created() {
    var unwatch = this.$watch('list', function() {
      // データlistが変更されたらeditedをtrueにする
      this.edited = true
      // データが変更されたら監視を解除
      unwatch()
    }, {
      deep: true
    })
  }
})
```