【Vuex】Vue CLIでVuexを簡単に始める

以前にこちらの記事を投稿したんですが、今回は``Vue CLI``で同じことを試してみます。
[【Vuex】CDNでVuexの最初の一歩を踏み出す](https://qiita.com/yukibe/items/3adb958a6d4d60d8a8bc)

# Vue CLIのプロジェクト作成
前提として、Vue CLIの起動に必要なパッケージは全てグローバルインストールされている状態です。
[【Vue.js】Vue CLIでVue.jsを動かす〜プロジェクト作成まで](https://qiita.com/yukibe/items/fac6d6c45dd308e3d7dc)

```
$ vue init webpack my_vuex_test
```

# Vuexのインストール

```
$ npm install vuex
```

インストール後にパッケージの脆弱性や依存情報についてメッセージが出力されますが、学習用のため、今回はこのまま進めました。

# ディレクトリ構造
``srcディレクトリ``直下の既存ファイルを若干編集しています。
使用しているファイルに限定すると、以下の構造になります。

```
src
  ├── components
  │   ├── App.vue      // 編集
  │   └── Counter.vue  // 新規ファイル
  ├── main.js          // 編集
  └── store            // 新規ディレクトリ
      └── index.js     // 新規ファイル

// 最終的に、ルートディレクトリ直下の``index.html``により出力される
```

# 用語の確認
簡単に確認します。
内容は公式サイトからの引用です。

説明だけだと分かりにくいので、実際に使いながら覚えていきます・・・

## ストア
信頼できる唯一の情報源。
アプリ1つにつき、1つだけ作ることができる。

>Vuex アプリケーションの中心にあるものはストアです。"ストア" は、基本的にアプリケーションの 状態（state） を保持するコンテナです。

## ステート
ストアの状態そのもの。
ストアの状態はここから呼び出される。

>Vuex は 単一ステートツリー (single state tree) を使います。つまり、この単一なオブジェクトはアプリケーションレベルの状態が全て含まれており、"信頼できる唯一の情報源 (single source of truth)" として機能します。これは、通常、アプリケーションごとに1つしかストアは持たないことを意味します。単一ステートツリーは状態の特定の部分を見つけること、デバッグのために現在のアプリケーションの状態のスナップショットを撮ることを容易にします。

## ミューテーション
ストアの状態を変更する手段。

>実際に Vuex のストアの状態を変更できる唯一の方法は、ミューテーションをコミットすることです。Vuex のミューテーションはイベントにとても近い概念です: 各ミューテーションはタイプとハンドラを持ちます。ハンドラ関数は Vuex の状態（state）を第1引数として取得し、実際に状態の変更を行います。

# ソースコード
## 処理の流れ
このようになるかと思います。

1. ``store/index.js``でストアをセットする
2. ``main.js``でストアをimportする
3. main.jsに``storeオプション``を設定し、コンポーネントにストアを注入する
4. 同じくmain.jsでimportしている``App.vue``に、注入されたストアが反映される
5. App.vueからimportしている``Counter.vue``にも、注入されたストアが反映される

公式サイトより引用します。
>ルートインスタンスに store オプションを渡すことで、渡されたストアをルートの全ての子コンポーネントに注入します。これは this.$store で各コンポーネントから参照することができます。

ルートのmain.jsで``storeオプション``を使用することにより、枝葉であるコンポーネントへストアが注入されます。
注入されたストアは、``this.$store.state.count``という書き方でApp.vueとCounter.vueの双方から呼び出しています。

store/index.jsとmain.jsで``store.commit('increment')``を行なっているため、最終的に``count``の結果は``2``になります。

``npm run dev``でサーバーを立ち上げると、ブラウザ上で確認できます。

## index.html
特に編集はしていません。

```index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>my_vuex_test</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
```

## main.js

```main.js
import Vue from 'vue';
import Vuex from 'vuex';

// index.jsの場合はファイル名を指定する必要はない
import store from './store'

import App from './components/App'

Vue.use(Vuex);

new Vue({
  el: '#app',
  store,
  components: { App },
  template: '<App/>' // '<app></app>'でも可
})

store.commit('increment')
```

## store/index.js

```store/index.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  }
})

store.commit('increment')

export default store
```

## App.vue

```App.vue
<template>
  <div id="app">
    <p>App: {{ count }}</p>
    <Counter/>
  </div>
</template>

<script>
import Counter from './Counter'

const App = {
  components: {
    Counter
  },
  computed: {
    count() {
      return this.$store.state.count
    }
  }
}

export default App
</script>
```

## Counter.vue

```Counter.vue
<template>
  <div id="counter">
    <p>Counter: {{ count }}</p>
  </div>
</template>

<script>
  const Counter = {
    computed: {
      count() {
        return this.$store.state.count
      }
    }
  }

  export default Counter
</script>
```

Vuexには他にもgettersなどの機能がありますが、少しずつ進めていきます。