vue.jsの使い方の基礎＃２【computed/methods/watch】


ドキュメントに沿って手を動かしたことを自分用教科書として書いていきます（算出プロパティとウォッチャの部分）
[公式ドキュメント](https://jp.vuejs.org/v2/guide/computed.html)とやっていることは基本的に同じです。覚えたことのアウトプットと、わからなかったことを調べて補足して書いている感じです。
誰かの参考になればうれしいです。

公式ドキュメントのはじめに～テンプレート構文までは前回記事にまとめたのでそちらもよければ見てみて下さい。
vue基礎系の記事一覧はこちら（随時更新）

https://qiita.com/kty000/items/c919e01fc0c118098eb9

#算出プロパティの書き方【computed】
vueでは、単一の式であればテンプレート内にJavaScriptをかけます。

```Index.vue
<div id="example">
  {{ message.split('').reverse().join('') }}
</div>
```

上のサンプルでは`message`を逆にして表示しています。
１回ならいいのですがもし`message`を逆にして表示したい場面が２回３回とあった場合にサンプルのを毎回書いていたら面倒なうえにちょっと見づらいので算出プロパティ（computed）を使いましょう。

```Index.vue
<template>
  <div id="app">
      <p>{{ message }}</p>
      <p>{{ reversedMessage }}</p>
  </div>
</template>

<script>
export default {
    data() {
        return {
            message: "こんにちは"
        }
    },
    computed: {
        reversedMessage() {
            return this.message.split('').reverse().join('')
        }
    }
}
</script>
```


>Vue は vm.reversedMessage が vm.message に依存していることを知っているので、vm.message が変わると vm.reversedMessage に依存する全てのバインディングを更新します


例えば`message`が「こんにちは」から「こんばんは」に変わったら、`reversedMessage`も更新されます。試してみました。

```Index.vue
<template>
  <div id="app">
      <p>{{ message }}</p>
      <p>{{ reversedMessage }}</p>
      <button @click="changeText">ボタン</button>
  </div>
</template>

<script>

export default {
    data() {
        return {
            message: "こんにちは",
        }
    },
    computed: {
        reversedMessage() {
            return this.message.split('').reverse().join('')
        }
    },
    methods:{
      changeText(){
        this.message = "こんばんは"
      }
    }
}
</script>
```

ボタンを押したら`message`が変わるようにしました。
実行結果↓
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/f2a57252-4dd1-352b-7c7a-d4cf3ab3687b.png)
ボタンを押下すると↓
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/54a5ba26-5bf8-9a31-1f48-e9d50d0c8041.png)
`reversedMessage`も変わりました。

##算出setter関数
>算出プロパティはデフォルトでは getter 関数のみですが、必要があれば setter 関数も使えます

setterも使えるらしい。公式を参考に書いてみました。ちょっと不自然かもですがsetterの動きの理解が目的なので大目に見てください。。

```Index.vue
<template>
  <div id="app">
      <p> 姓：{{ lastName }}</p>
      <p> 名：{{ firstName }}</p>
      <p> {{ fullName }}</p>
      <button @click="changeFullName()">名字を鈴木に変更</button>
  </div>
</template>

<script>

export default {
    data() {
        return {
            lastName: "山田",
            firstName: "太郎",
        }
    },
    computed: {
        fullName: {
            // getter 関数
            get: function () {
                console.log("get実行")
                return this.lastName + '　' + this.firstName
            },
            // setter 関数
            set: function (newValue) {
                console.log("set実行")
                var names = newValue.split('　')
                this.lastName = names[0]
            }
        }
    },
    methods:{
        changeFullName() {
            this.fullName = "鈴木　太郎"
        }
    }
}
```

実行結果
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/7b945d55-661e-23f7-1745-3f2ab54dee31.png)
最初の描画で`fullName`が呼ばれているのでgetが一度実行されています。
ボタンを押下すると↓
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/703f0eb7-b7d4-7e1d-7bbb-77d8df525355.png)
setとgetが呼ばれました。

①`this.fullName = "鈴木　太郎"`で`fullName`のsetterが呼ばれる
②setterを実行（`lastName`をセット）
③`fullName `が依存している`lastName`が変わったのでgetterを実行

という流れになります。慣れるまでプロパティ設計するの悩みそうです。。




#メソッドの書き方【method】
先ほど`message`を逆にするプロパティを作成しましたが、関数としてメソッドにすればよくない？と思って読み進めていたら同じこと公式も書いてた。じゃあ書いてみましょう。

```Index.vue
<template>
  <div id="app">
      <p>{{ message }}</p>
      <p>{{ reversedMessage() }}</p>  --()をつけること！
  </div>
</template>

<script>

export default {
    data() {
        return {
            message: "こんにちは",
        }
    },
    methods:{
        reversedMessage() {
          return this.message.split('').reverse().join('')
        },
    }
}
</script>
```

私もよく忘れるのですが、メソッドは関数なので()が必要になります。
実行するとこちらも「こんにちは」と「はちにんこ」が画面に表示されました。
また、先ほど同様に`message`を変更するボタンを追加して実行しても同様の結果が得られました。
>メソッド呼び出しは、再描画が起きると常に関数を実行します。


#computedとmethodsの違い
同じ動きするなら結局何が違うのか、ふんわりとしか理解できなかったのでちょっと調べた。

**算出プロパティはリアクティブな依存関係にもとづきキャッシュされます**
既存のデータをごにゃごにゃするときに使います。
一度プロパティを実行すれば、その後同じ算出プロパティが呼び出された際も以前キャッシュされたデータを返すだけなので何度も同じ処理を行うということはありません。

依存するデータが変われば処理するし、処理したことは覚えてるから呼ばれたら覚えてることを返すよ。データが変わったり呼ばれたりしなければ何もしないよ～ということです。



**メソッドは再描画が起きると常に関数を実行します**
メソッドさんは超働き者なので、呼ばれれば毎回動いてくれますし、再描画が起きた時も動いてくれます。

文字で書いてもわからないのでいくつかサンプルで動かしてみました。
##サンプルコード１

```Index.vue 
<template>
  <div id="app">
      <p>computed: {{ computedNumber }}</p>
      <p>computed: {{ computedNumber }}</p>
      <p>methods: {{ methodsNumber() }}</p>
      <p>methods {{ methodsNumber() }}</p>
  </div>
</template>

<script>

export default {
    computed: {
        computedNumber() {
            return Math.random();
        }
    },
    methods:{
        methodsNumber() {
            return Math.random();
        }
    }
}
</script>
```
実行結果
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/d04d3289-52e9-9d54-3495-486eb9c604b9.png)
ランダムな数字を生成する処理を行っています。
computedは一度実行したらキャッシュしたものを返すだけなので同じものが返ってきました。
methodsは呼ばれるたびに処理してくれるので今回２回処理された結果、違う結果が返ってきています。

##サンプルコード２

```index.vue
<template>
  <div id="app">
    <p>computed:  {{ computedCounter }}</p>
    <p>methods :  {{ methodsCounter() }}</p>
    <button @click="count += 1">+1ボタン</button>

    <p>{{ text }}</p>
    <input type="text" v-model="text" />
  </div>
</template>

<script>

export default {
    data() {
        return {
            count: 0,
            text: "こんにちは"
        }
    },
    computed: {
        computedCounter() {
            console.log("computed実行")
            return this.count
        },
    },
    methods:{
        methodsCounter() {
            console.log("methods実行")
            return this.count
        }
    }
}
</script>
```


ボタンを押すと数字が１づつ増えます。
また、それと全く無関係の入力フィールドを`v-model`を使用して作成しました。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/1d390231-e023-2bd0-c8bb-25a119e8c141.png)


+1ボタンを押下すると、プロパティとメソッドのどちらも動きました。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/10177080-835b-3699-b23c-d30e8bf80f20.png)

では下の入力フィールドいじってみるとどうでしょうか？
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/57541a07-064c-6254-0494-19a80e706905.png)
「ち」の削除時と「は」の削除時の２回methodが動きました。
v-modelで表示させている`text`は、当然入力情報が変われば表示も変わる、つまり**再描画**されます。
**メソッドは再描画が起きると常に関数を実行します**ので、今回２回動いたというわけです。
やたらめったらmethodsを使用すると、行わなくてよい処理を行ってしまう場合があるのでうまく使い分ける必要がありそうです。

##違いまとめ
ちょっとごちゃっと書いてしまったので箇条書きでまとめます
###computed
・算出プロパティ
・既存のデータに何か処理を与えるプロパティにしたいときに使用
・結果をキャッシュする
・一度プロパティを実行すれば、再度算出プロパティが呼び出された際もキャッシュされたデータを返す
・getterとsetterが使用可能(デフォルトはgetterのみ)

###methods
・メソッド（関数）
・呼び出す際は()が必要
・キャッシュされない
・一度実行した場合も再度メソッドが呼び出されるたびに計算を行う
・getterのみ使用可能（setterは不可）

##どのような場面で使うべきか
例えば、ユーザーに何かしらの入力をさせて、それを即時画面に反映させたいとき。
ネットショッピングでほしい個数を入力させたら小計と合計を出す。などですね。
この場合は`computed`がよさそうです。

`methods`はクリック時やマウスオーバー時などなにかアクションが起きた場合に使用するといいです。
先ほどのネットショッピングの例でいうと、購入ボタンを押したときの処理などですね。


基本的に余計な処理を行わなくて済む`computed`が使用できるなら、優先して使った方がよさそうです。
#監視プロパティの書き方【watch】
>Vue インスタンス上のデータの変更を監視し反応させることができる、より汎用的な 監視プロパティ(watched property) を提供しています。
多くの場合では算出プロパティの方が適切ではありますが、カスタムウォッチャが必要な時もあるでしょう。データの変更に対して反応する、より汎用的な watch オプションを Vue が提供しているのはそのためです。データが変わるのに応じて非同期やコストの高い処理を実行したいときに最も便利です。


たとえば、算出プロパティ`reversedMessage`は`message`を監視して変更があったら実行します。このように算出プロパティでも十分監視の役目は果たせるので基本は算出プロパティのほうが適切のようです。すっきりかけるし。

公式の引用にもありますが**データが変わるのに応じて非同期やコストの高い処理を実行したいときに最も便利**のようです。

ここは今の私の知識ではいい書き方やサンプルが思いつかなかったので勉強進めた後に何かあれば書いてみます。
公式の例を見るのがわかりやすいので参考にしてみてください。

https://jp.vuejs.org/v2/guide/computed.html#%E3%82%A6%E3%82%A9%E3%83%83%E3%83%81%E3%83%A3


#さいごに
勉強を進めていく上で必要に応じて随時追記していきます。
間違い等何かあればコメントいただけると幸いです。

最後まで読んでいただいてありがとうございます！