とりあえず最短でVuexを使えるようにする

# 前回までのあらすじ

前回([子コンポーネントから親コンポーネントへのイベント送信](https://qiita.com/mkiuchi/items/413af10d80f26e448173#%E5%AD%90%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%8B%E3%82%89%E8%A6%AA%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%B8%E3%81%AE%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E9%80%81%E4%BF%A1))やった内容だと直接の親子の間しかプロパティの受け渡しができない。実際にはアプリケーション全体の設定値を個々のコンポーネントに反映させたり、モーダルウィンドウを表示させたりするので、コンポーネント間をジャンプして値を渡したいことがある。

Vue.js でこれをやるには2種類の方法があって、

- Vue のプロトタイプに追加することでグローバル変数っぽい扱いができる
- [Vuex](https://vuex.vuejs.org/ja/)を使う

Vueプロトタイプについては[ドキュメント](https://jp.vuejs.org/v2/cookbook/adding-instance-properties.html)を読んでみたもののよくわからんというところがあり、Vuexはそれなりに情報もあったし以前から気にもなっていたので、まあこの機会にやってみるか、と思った。

# インストール方法

正直[公式ドキュメント](https://vuex.vuejs.org/ja/installation.html)を読んでもよくわからなかった。自分で試行錯誤してみて、こんな感じかなと思ったことを書いておく。

## 1. npm install --save vuex

```shell
npm install --save vuex
```

他のドキュメントでは vuex-router-sync も入れるなど書いてあるがよくわからなかった。使ってない。

## 2. main.js の修正

router, components ディレクトリと同じ階層で store ディレクトリを手で作る。main.jsを以下のように修正して、 `import store from './store'` と `store: store,` を追加

```javascript:main.js
import Vue from 'vue'
import store from './store'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store: store,
  router,
  components: { App },
  template: '<App/>'
})
```

## 3. store/index.js の作成

こんな感じ。[公式のチュートリアル](https://vuex.vuejs.org/ja/guide/)がいきなりES2015前提になってるのでよくわからなかったがなんか以下のような感じでいいっぽい。解説は他のドキュメントにいろいろ書かれているのでそちらを。

このへんは見るドキュメントによってバラバラなので正直しんどかった。

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

Vue.use(Vuex)

const state = {
  count: 0
}

const mutations = {
  countUp (state, payload) {
    state.count += 1
  }
}

const actions = {
  countUp ({commit}, payload) {
    commit('countUp', payload)
  }
}

const getters = {
  count: state => {
    return state.count
  }
}

export default new Vuex.Store({
  state: state,
  mutations: mutations,
  actions: actions,
  getters: getters
})
```

これでとりあえず `npm run dev` して動けばOK。値が増えていった時にファイルを分けたりもできるみたいだけどそれはまた後で・・・。

# Vuexの使い方

このへんも公式ドキュメントやら他のドキュメントやら記述がバラバラだったり動くと書かれているものが動かなかったりアレだったが、とりあえず自分的には以下の方法で動いた。

## 値のセット方法

まず事前に store/index.js に値の定義(state/getter/mutation/action)を一式書いておく必要がある。

次にコンポーネントから呼び出す。公式にはmutation(=commit?)してからaction(=dispatch?)でコミット、的に書いてあるが、実際にそうすると2回値を更新してしまうようで、結果としてはmutation(=commit?)抜きのaction(=dispatch?)だけでよかった。

```javascript:SetTestComponent.vue
  methods: {
    onClick: function (event) {
      console.log('progdetailclicked')
      // this.$store.commit('countUp')
      this.$store.dispatch('countUp').then(
        console.log('commited.')
      )
    }
  },
```

## 値の取得方法

[公式](https://vuex.vuejs.org/ja/guide/getters.html)だとcomputedで取れるよ！的な感じだけど、なぜか自分のところではぜんぜん動かなくてハマった。

結局値を取る側では computed に加えて watch にもフックを仕掛けておくようにしたらうまく取れた。以下のような感じ。

```javascript:GetTestComponent.vue
  computed: {
    count: function () {
      // console.log('GetTestComponent-computed-count')
      // console.log(this.$store.getters.count)
      return this.$store.getters.count
    }
  },
  watch: {
    count: function () {}
  }
```

いろいろ動かしてみた限りでは、以下のような挙動だった。

- 画面を描画した時には `computed` のみ呼び出される
- 値が更新した時には `watch`, `computed` が呼び出される。ただしじゃあ `computed` だけでいいじゃんって `computed` のみを定義しておくと、値が更新されても呼び出されない


自分用メモなので厳密さは勘弁してください。正しいことが知りたい人は専門家に聞いてね！