Vue.js用のFluxライクなライブラリVuexを試してみる

## まえがき
Vue.js用のFluxライクなライブラリVuexを試してみました。

[Vuex](https://github.com/vuejs/vuex)

注意：まだ開発中でAPIも変わる可能性があります（2015/12/25）

2017/12/17　追記

改めて学び直してみました。

https://qiita.com/nasum/items/d17c0a628e6c32616b85

## データの流れ

詳しくはドキュメントを読んだ方が正確だけど、この図だけ見れば何となくやりたいことがわかるはず。

![vuex.png](https://qiita-image-store.s3.amazonaws.com/0/11510/10350588-65c6-61c2-7daf-aa89755ac40a.png "vuex.png")

何となくFluxっぽいですね。

自分の理解としては

1. コンポーネントからActionを呼び出してそこで外部のAPIと通信してデータを取得
2. Mutationでデータをセット
3. Stateがコンポーネントの数値をアップデート

という流れ（間違ってたらすみません）。

Vue.jsは値の取得に対しては関与しないフレームワークですが、Vuexを入れることにより値の取得からセットまでライブラリで制御できるので、無秩序になりがちだったVue.jsを使ったアプリケーションに秩序をもたらすことが出来そうです。

## 作った物

作った物はおなじみToDoList。横着して値の追加しか対応していません。

![vuex.gif](https://qiita-image-store.s3.amazonaws.com/0/11510/4eb38d5a-0942-42d8-9ea7-0c9db090d8fa.gif "vuex.gif")

## コードと解説

Vueifyを使ってコンパイルすることを前提としているので、.vueなる拡張子が出てくるので注意。

まずはstoreから

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

Vue.use(Vuex);

const state = {
  input: "",
  todos: []
}

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

```

```javascript:actions.js
export default {
  addTodo: 'ADD_TODO'
}
```
```javascript:mutations.js
export default {
  ADD_TODO (state, text) {
    state.todos.push(text)
  }
}
```

`Vue.use(Vuex)`でセットアップします。

stateだけここで定義してactionsとmutationsは別ファイルにしていますが、ここは好みだと思います。

actionsではここは簡単に`ADD_TODO`にdispatchしています。外部からajaxで値を持ってくるときなどはここに書くと良さそうです。

mutationsでは`ADD_TODO`を定義しています。これは`input`タグの`keyup`に紐付けられた関数から呼び出されて`state`の`todos`に値を追加することを想定して作られています。


次に親VieModel。

```javascript:index.js
import Vue      from 'Vue';
import TextForm from './components/TextForm.vue';
import ToDoList from './components/ToDoList.vue';
import store    from './store/';

window.onload = function(){
  var main = new Vue({
    el: "body",
    data: store.state,
    components: {
      "text-form": TextForm,
      "to-do-list": ToDoList
    }
  })
}

```

Vueとコンポーネント、それとVuexで作ったstoreを読み込みます。
そして親ViewMoelにstoreとコンポーネントをセットします。

data属性には`store.state`を入れることで動的に`state`の中身を変えたときに各コンポーネントに反映するようにしています。

次にコンポーネント。

```html:TextForm.vue
<template>
  <div>
    <input type="text" v-model="input" @keyup.enter="addTodo"/>
  </div>
</template>

<script>
  import store from '../store/';

  export default {
    props: ['input'],
    methods: {
      addTodo: function(e){
        var text = e.target.value;
        store.actions.addTodo(text);
        e.target.value = '';
      }
    }
  }
</script>
```
```html:ToDoList.vue
<template>
  <ul>
    <li v-for="todo in todos">{{todo}}</li>
  </ul>
</template>

<script>
  export default {
    props: ['todos']
  }
</script>

```
コンポーネントは`props`で渡したデータを元に描画を行っています。

`actions`で定義した`addToDo`をここで呼び出しています。

気をつけることとして、`mutations`で定義した`addToDo`は`state`と`text`の二つの引数を必要としていたのですが、`actions`経由で呼び出すときには引数は`text`だけでいいと言うことです。ちょっと調べ切れていないのですが、`actions`で呼び出すかていでよろしくやっているもと思われます（詳しくはコードを読んでみよう）。一瞬ちょっと違和感を感じてしまいますね。

`addToDo`に渡されたデータを使って`todos`が更新され、Todoリストが更新されるようになっています。

## おわり・感想

まだ使ってみたレベルの話ですが、うまく使えばVue.jsをつかってやっていた開発の辛いところを解消が出来る感触があります。

Vueを使ってFluxをやるときはReduxを使うというやり方もありますが([Vue.jsにreduxを載せた話](http://blog.mmmcorp.co.jp/blog/2015/12/03/vue-with-redux/))。Vue独自のFluxライクな実装が出てきたことにより、Vueに適したやり方も出来るようになってきたのではないでしょうか。

これ以上ライブラリが増えて辛いという面もありますが、追っていくのも楽しそうです。


## 参考URL

* [Vuex](https://github.com/vuejs/vuex)
* [introduction](http://vuex.vuejs.org/en/intro.html)
* [作ったサンプル](https://github.com/nasum/vuex-practice)