構造の複雑さとVuex書き分け

[Vue.js Advent Calendar 2016](http://qiita.com/advent-calendar/2016/vue) 14日目です。

Vue2 + Vuex2の組み合わせはVueを正しくfluxに導き、より巨大なアーキテクチャを管理できるようになった。
逆に言うとVueの気軽さが失われてしまったのでは、という印象を持つ方もいらっしゃるのでは。

しばらく使ってみたら肩の力の抜き方が分かってきたので、構造の複雑さ別に書き方をまとめてみる。

このポストは

```
"vue": "^2.1.4"
"vuex": "^2.0.0"
```

の提供でお送りします。

# Level 1

子コンポーネントとか存在しない。単一のVueコンポーネントで完結する。
勿論Vuexも要らない。

``` js:main.js
new Vue({
  data: {
    hello: false
  },
  methods: {
    sayHello () {
      this.$emit('hello')
    }
  },
  created () {
    this.$on('hello', () => {
      this.$data.hello = true
    })
  }
})
```

イベントを介さずお互いにthis.methodName()で呼び出しても良い気もする。

# Level 2

いくつかの子コンポーネントが存在するが、Vuexは使わない。
`v-on`ディレクティブによって子コンポーネントからイベントを親に伝達することができる。

```
<hello-component @my-event="onHelloEvent"></hello-component>
```

ちょっとした子→親へのイベント伝達ならこれでも良いが、スケールしづらい。

# Level 3

いくつか子コンポーネントが存在し、何層かの構造が出来つつある複雑さ。
管理するためにVuexを導入してみる段階。
モジュールのないStore程度なら以下の通り適当でもやっていける。

Vuex exampleだと[todomvc](https://github.com/vuejs/vuex/tree/dev/examples/todomvc)の書き方が丁度良いのではないでしょうか。

``` js:store.js
// 基本的なStore部分
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    hello: true
  },
  mutations: {
    bye (state) {
      state.hello = false
    }
  }
})
```

### Getters と computed

複数コンポーネントでGettersを使い回す予定が無いなら、`getters`に書かずに`computed`で宣言してもいい。

``` js:app.js
import * as types from './store/types'

export default {
  computed: {
    hello () {
      return this.$store.state.hello
    }
  }
}
```

### Actions と methods

`methods`の中で`commit`も邪道ではない。
StoreにActionsを書かなくてもやっていける。

``` js:methods
methods: {
  sayHello () {
    this.$store.commit('hello')
  }
}
```

更に、Mutationsをmethodsの中に呼び出せる。
こんがらがったらちゃんと分割した方が良さそう。

``` js:methods
methods: {
  sayHello () {
    this.$emit('hello')
  },
  ...mapMutations([
    'bye'
  ])
}
```

``` html:html
<button @click="bye">BYE</button>
```

適当さ加減の原動力は「ストアとコンポーネントの行き来が面倒」に尽きる。

# Level 4

複雑にデータもコンポーネントも重なっていてヤバい。

Gettersで出力を管理し、
Mutationsもファイルに分けて書くし、
MutationTypesもモジュールごとに定数で管理する。

モジュール分割や命名など、要件によって変わると思うので個人的に頻出するものを書く。

### 名前空間

モジュールごとに名前空間を付けないと管理しきれない。

```js:modules/hello/type.js
const namespace = 'hello/'
export const HELLO  = namespace + 'HELLO'
export const SAY_HELLO   = namespace + 'SAY_HELLO'
export const TOGGLE_DONE = namespace + 'TOGGLE_DONE'
```

```js:modules/hello/index.js
import * as types from './types'

export default helloModule = {
  state: {
    hello: false,
  },
  getters: {
    [types.HELLO] (state) {
      return state.hello
    }
  },
  actions: {
    [types.SAY_HELLO] (context, payload) {
      api.sayHello()
        .then((data) => {})
        .catch((err) => {})
    }
  },
  mutations: {
    [types.HELLO] (state, payload) {
      state.hello = true
    }
  }
}
```

actionsもgettersも定数になるのは個人的に気持ち悪いのですが、
多分これが一番混乱しないと思います。

### Data と State

```js:ex.js
export default {
  data () {
    isLoading: false,
    isVisible: false
  }
}
```

個々のコンポーネントが持つ`data`の使い所とは。
「読み込み中はローダーを表示する」時、StoreにViewのために`isLoading`が生えるのは宜しくない。
`methods`上で`querySelector()`するよりは、`data`に`isLoading`を生やして、`v-class`で状態管理した方がよさげ。

個人的には、アプリケーションとしてのデータに関係ないが見た目を管理したい時は`methods`と`data`で管理し、データのロジックはActionsとMutationsに任せるよう分けている。

## まとめ

ドキュメントや使ってみたでは行儀の良い書き方が書かれていて「Vue2.0で書き方が複雑になってるのでは」と尻込みしてしまうこともあるかもしれないが、慣れてくるとそんなこともなかった。
個人レベルでLevel 4までガッチガチに設計固めて作る必要も無いので、程度に肩の力を抜いてVuexを楽しんでほしい。
Vueは2.0でも適当に書いてなんとかなるフレームワークです。


## 参考資料

[Vuex Docs](http://vuex.vuejs.org/)
[Vuex examples](https://github.com/vuejs/vuex/tree/dev/examples/)