【Vue.js】複数のカウントボタンを、それぞれ押下した数だけカウントさせたい【Component】

# 問題
Vue.jsのComponentの勉強のため、カウンターを作っていたときのことです。

１つのボタンを押したら、**他のボタンのカウントも増えてしまう問題**が発生。

![20200304_vue_before.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575953/902d058e-9d01-3535-05cf-4e0eb972ddf9.gif)


# 環境
- Vue.js v2.6.11（CDN）

# コード
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Components</title>
  <link rel="stylesheet" href="css/styles.css">
</head>
<body>
  <div id="app">
    <button-counter message="Counter A"></button-counter>
    <button-counter message="Counter B"></button-counter>
    <button-counter message="Counter C"></button-counter>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
  <script src="js/main.js"></script>
</body>
</html>
```

```js:js/main.js
(function () {
  'use strict';

  const counter = {
    count: 0
  };

  const countComponent = Vue.extend({
    template: '<button @click="countUp">{{ message }}: {{ count }}</button>',
    props: {
      message: {
        type: String,
      },
    },
    data: function () {
      return counter;
    },
    methods: {
      countUp: function () {
        this.count++;
      },
    },
  });

  const vm = new Vue({
    el: '#app',
    components: {
      'button-counter': countComponent,
    },
  });
})();
```


# 原因
リファレンスを読むと、

> コンポーネントの data オプションは関数でなければなりません。各インスタンスが返されるデータオブジェクトの独立したコピーを保持できるためです:

という記述がありました。
参照:[【Vue.js ガイド】data は関数でなければなりません](https://jp.vuejs.org/v2/guide/components.html#data-%E3%81%AF%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93)

それぞれのカウントボタンインスタンスに返される値を独立させるために、**dataオプションを関数にしなければならない**のですね。


# 解決
リファレンスに記述の仕方がちゃんと書いてありました。

> ```js
data: function () {
  return {
    count: 0
  }
}
```
Vue にこのルールがない場合、ボタンを1つクリックすると、以下のようにすべての他のインスタンスのデータに影響します:

丁寧に今回の事象の例も提示してありました。


修正後はこうなりました。

``````js:js/main.js
(function () {
  'use strict';

  // 削除
  // const counter = {
  //   count: 0
  // };

  const countComponent = Vue.extend({
    template: '<button @click="countUp">{{ message }}: {{ count }}</button>',
    props: {
      message: {
        type: String,
      },
    },
    // 変更-----
    data: function () {
      return {
        count: 0,
      };
    },
    // -----
    methods: {
      countUp: function () {
        this.count++;
      },
    },
  });

  const vm = new Vue({
    el: '#app',
    components: {
      'button-counter': countComponent,
    },
  });
})();
```

ちゃんとそれぞれのボタンの押下数をカウントしてくれるようになりました。
![20200304_vue_after.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575953/45b49fa4-26e3-a96f-44f7-dbef956fc7f4.gif)

# 反省
ちなみにcountComponentの中でdataオプションを関数にしないままcountを定義しようとすると、Vue.jsの方で`ReferenceError: count is not defined`と、エラーになることを教えてくれました。
<img width="524" alt="スクリーンショット 2020-03-04 16.47.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575953/5617c766-af3a-5853-6a76-16158008bde9.png">

そもそも、countは別で定義するのではなく、処理をしているインスタンス内で設定すればよかったのですね。

# 参照
[【Vue.js ガイド】data は関数でなければなりません](https://jp.vuejs.org/v2/guide/components.html#data-%E3%81%AF%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93)