Vue初心者のvuex入門

Vue.jsの学習過程で、vuexについて学んだ事、疑問、感じた事をまとめた記事になります。
私と同じようにVue（Vuex）初心者の方の少しでも参考になれば幸いです。

## Vuexはいつ導入すべきなのか？

これは、私がVuexを学習し始めた頃に感じた疑問です。
シンプルなSPAを作成している場合、返ってコードが冗長になってしまって、導入するメリットがないのではないかと思いました。
[公式ドキュメント](https://vuex.vuejs.org/ja/)には、こう書いてありました。

> あなたが大規模な SPA を構築することなく、Vuex を導入した場合、冗長で恐ろしいと感じるかもしれません。そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。

つまり、大規模なSPAを構築しないのであれば導入の恩恵を受けにくいという事です。

私はVuexの学習をする際に、node.jsのexpressで作ったAPIサーバーとVue.js(Vuex)を使ってシンプルなタスク管理アプリを作成しました。
この場合、シンプルなSPAなのでVuexの導入メリットはあまり無さそうだなと思いました。
しかし、ここで気をつけなければいけない事が一つありました。
今回作成するシンプルなタスク管理アプリは、一生シンプルなままなのかという事。
最初はシンプルでも、後から色々な機能を実装していき、複雑になっていくのではないか。そもそもそうじゃないと楽しくなくない？と感じました。
この辺りを考慮して、最初から導入しておくのが無難なのかなと感じました。
ある程度、形ができたアプリに状態管理を導入するのは、大変だと思うので。

## Vuexで状態管理する範囲

Vuexには、state、mutations、actions、gettersがあり、storeのstateで状態管理をします。
私は、最初すべての状態をstoreのstateで管理しようとしていましたが、返って状態管理がしにくくなり、コードが冗長になってしまいました。
こちらも[公式ドキュメント](https://vuex.vuejs.org/ja/guide/state.html)に書かれています。

> Vuex を使うということは、全ての状態を Vuex の中に置くべき、というわけではありません。多くの状態を Vuex に置くことで、状態の変更がさらに明示的、デバッグ可能になりますが、ときにはコードを冗長でまわりくどいものにします。状態の一部がひとつのコンポーネントだけに属している場合は、それをローカルの状態として残しておくとよいでしょう。

つまり、コンポーネントをまたがないデータに関しては、無理にVuexで管理しないで、コンポーネントで管理すれば良いみたいですね。

## Vuexでの状態管理

まず状態管理を行う為に、storeを作成します。
今回は、コンポーネントから受け取った値でstateのtextを更新するものとします。

```javascript
import vue from 'vue'
import Vuex from 'Vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    text: ''
  },
  getters: {
    todos(state) {
      return state.text
    }
  },
  mutations: {
    setTodo(state, data) {
      state.text = data
    }
  },
  actions: {
    updateTodos({ commit }, data) {
      commit('setTodo', data)
    }
  }
})
```



## getters

ゲッターは、主にstateのデータを表示したい時に使います。

gettersでstateを取得します。

```js
getters: {
  todos(state) {
    return state.text
  }
}
```

そしてコンポーネント側で、

```javascript
computed: {
  todos() {
    this.$store.getters.todos
  }
}
```

で呼び出す事ができます。

また、storeのgettersをコンポーネントのcomputedにマッピングする`mapGetters`ヘルパーを使用して呼び出す事もできます。

```js
import { mapGetters } from 'vuex'

computed: mapGetters([
  'todos'
])
```

computed内で使用したい場合は、スプレッド演算子を使います。

```js
computed: {
  ...mapGetters([
    'todos'
  ])
}
```

このように、ヘルパーを使う事でコードがすっきりします。

## mutations

値を受け取って、stateを書き換えるところ。mutations以外で値の更新を行なってはいけない。
mutationsは同期的でなければならい。

ミューテーションはcommit関数を使用して発火させます。

```js
actions: {
  updateTodos({ commit }, data) {
    commit('setTodo', data)
  }
}
```

この場合だと、actions内の`commit('setTodo', data)`の部分で発火させています。

第一引数に呼び出す関数名(タイプ)、第二引数にmutationsに渡したい値(ペイロード)を指定します。

```js
mutations: {
  setTodo(state, data) {
    state.text = data
  }
}
```

呼び出されたミューテーション側でも第二引数でペイロードを受け取ります。

コンポーネント内で、ミューテーションを呼び出すには、

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

で呼び出します。

ミューテーションもゲッター同様ヘルパーを使用する事もできます。

```js
import { mapMutations } from 'vuex'

methods: mapMutations([
  'setTodo'
])
```





## actions

アクションでは、ミューテーションをコミットします。アクションは、非同期処理を行う事ができるのでAPIサーバーとの通信など非同期的な処理はアクション内で行う事になります。



```js
actions: {
  updateTodos({ commit }, data) {
    commit('setTodo', data)
  }
}
```

第二引数にコンポーネントから受け取った値を指定する事ができます。

コンポーネント内でアクションを呼び出すには、

```js
methods: {
  updateTodos() {
    this.$store.dispatch('updateTodos')
  }
}
```

で呼び出す事ができます。

また、`store.dispatch`にマッピングする`mapActions`ヘルパーを使用して呼び出す事もできます。

```js
import { mapActions } from 'vuex'

export default {
  methods: mapActions([
    'updateTodos'
  ])
}
```

このようにして、コンポーネントから受け取った値をactions→mutations→stateと渡して行く事でVuexの一連の流れが完成します。

<img width="688" alt="スクリーンショット 2019-05-11 17.54.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264384/aba699e9-bb45-1d14-1845-28339c93f622.png">




## まとめ

今回は、Vuexの基本的な使い方について書きました。

私自身がまだ使いこなせていないので、徐々にSPAの規模を大きくしていきながら学び、また記事を書けたらたらと思っています。



Vue.jsは、[公式ドキュメント](https://vuex.vuejs.org/ja/)がとても丁寧でわかりやすいので、本当に助かります。