Vue.jsとVuexでTodoListを作ってみた

# はじめに

Vue.jsとVuexでTodoListを作ってみたので備忘録として書いていきます。

Vuexはまだ理解が浅いので間違っていたらすみません。

[成果物](https://theimaginationwasunbroken.com/vue-sample/src/vuex-todo-sample/)

~~※一瞬見えてはいけない何かが見えるのはご愛嬌・・・~~

[v-cloak](https://jp.vuejs.org/v2/api/index.html#v-cloak)というVueの機能で非表示にできました！ありがとうございます!(2017/9/10追記)

機能は「追加」と、「完了」と、「完了から戻す」3つだけ。

次の記事 [Vue.jsとVuexとwebpackでTodoListを作ってみた](http://qiita.com/tiwu_official/items/998fd4bd84bbda470ec4)

さらに次の記事 [Vue.jsとVuexとwebpackで単一ファイルコンポーネント化してTodoListを作ってみた](http://qiita.com/tiwu_official/items/6a877bcdf2c3022f0ff6)

## スペック

- JSは割とよく書く
- JSフレームワークはVue.jsを少しだけ
    - 大規模に使ったことはない
- Fluxは使ったこと無い

# Vue.js

[公式](https://jp.vuejs.org/)

少しだけ使ったことあるJSフレームワーク。

HTMLとJSとCSSの知識はあるのでなんとか書ける。


# Vuex

[公式](https://vuex.vuejs.org/ja/intro.html)

> Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリです。

とのこと。

> Flux、 Redux そして The Elm Architectureから影響を受けています。

らしい。

> 状態管理に関わる概念を定義、分離し、特定のルールを敷くことで、コードの構造と保守性を向上させることができます。

メリットとのこと。


![vuex.png](https://qiita-image-store.s3.amazonaws.com/0/81308/0cbf6b79-2bc1-5aca-3fca-d24567ab4930.png)

単一方向のデータフローで、グローバルシングルトンにすることでコンポーネント間のデータの受け渡しを取っ払うそうです。

# ソースコード解説

[全体](https://github.com/tiwuofficial/vue-sample/blob/master/src/vuex-todo-sample/index.html)

今回は1つのHTMLに書いていて、コンポーネント化など全くしていません・・・

※ソースコードは抜粋しています

## State

Todo ListとDone Listを定義。

```javascript
var store = new Vuex.Store({
  state: {
    todos: [],
    dones: []
  },
});

```

## Vue Components

ディスパッチの記述をstoreからthis.$storeに変更しました！コメントありがとうございます！(2017/9/11追記)

### Todo Input

入力された中身を受け取って、追加アクションをディスパッチ。

```html
<div class="wrap">
  <h2>Todo Input</h2>
  <input type="text" @keyup.enter="addTodoText"/>
</div>
```

```javascript
addTodoText: function(e){
  var text = e.target.value;
  this.$store.dispatch('addTodo', {
    text: text
  });
  e.target.value = '';
}
```

### Todo List

Todo Listの表示、完了アクションをディスパッチ。

```html
<div class="wrap">
  <h2>Todo List</h2>
  <ul>
    <li v-for="todo in todos">
      <p>ID : {{todo.id}}</p>
      <p>Text : {{todo.text}}</p>
      <button @click="doneTodo(todo.id)">Done</button>
    </li>
  </ul>
</div>
```

```javascript
doneTodo: function(id) {
  this.$store.dispatch('done', {
    id: id
  })
}
```

### Done List

Done Listの表示、完了から戻すアクションをディスパッチ。

```html
<div class="wrap">
  <h2>Done</h2>
  <ul>
    <li v-for="done in dones">
      <p>ID : {{done.id}}</p>
      <p>Text : {{done.text}}</p>
      <button @click="resetTodo(done.id)">Reset</button>
    </li>
  </ul>
</div>
```

```javascript
resetTodo: function(id) {
  this.$store.dispatch('reset', {
    id: id
  })
}
```

## Actions

それぞれ、ミューテーションをコミットする。

```javascript
actions: {
  addTodo (context, todo) {
    context.commit('ADD_TODO',todo.text);
  },
  done (context, todo) {
    context.commit('DONE_TODO',todo.id);
  },
  reset (context, todo) {
    context.commit('RESET_TODO',todo.id);
  }
}
```

## Mutations

ステートを変化させる。

Todo ListとDone Listに追加と削除をするだけ。

```javascript
mutations: {
  ADD_TODO (state, text) {
    var todo = {
      id: 0,
      text: text
    }
    if (state.todos.length !== 0) {
      todo.id = state.todos[state.todos.length -1].id + 1;
    }
    state.todos.push(todo);
  },
  DONE_TODO (state, id) {
    for (var i = 0; i < state.todos.length; i++) {
      if (state.todos[i].id === id) {
        state.dones.push(state.todos[i]);
        state.todos.splice(i, 1);
        break;
      }
    }
  },
  RESET_TODO (state, id) {
    var todo = {};
    for (var i = 0; i < state.dones.length; i++) {
      if (state.dones[i].id === id) {
        todo = state.dones[i];
        state.dones.splice(i, 1);
        break;
      }
    }
    state.todos.push(todo);
    state.todos.sort(function(a,b){
      if(a.id<b.id) return -1;
      if(a.id > b.id) return 1;
      return 0;
    })
  }
}
```

# 所感

ファイルを分割していけばどこに何が書かれているかわかりやすそう（今回は1つにまとめているが・・・）。

書きながらアクションの存在価値がわからなかったが、アクションは非同期処理が行えるのがメリットとのこと。

よくわからんと思いながら読んでいたら、ミューテーションは状態の変化をするため、必ず同期的に行うべしと書いてあり、非同期な処理による状態の更新（APIの返却値による状態の更新）のためにアクションが存在するらしい。

なるほど。