Vue.jsについての基礎(Nuxt.jsでのVuex)

#はじめに
おはようございます。こんにちは。こんばんは。
Watatakuです。
今回は以前[こちら](https://qiita.com/watataku/items/d3bf9a904aa3460f5af8)で書かせていただいた内容の中で「次回Vuexやるよー」と言っておきながらやっていなかったのでやっていきます。
#Vuexとは
> Vuex は複数のコンポーネント間で状態を共有するために使われる状態管理のライブラリです。 
> Vueのコンポーネントから状態管理の部分をVuex側に寄せることで、コンポーネント間のプロパティ渡しの連鎖による複雑さを回避できます。

#使い方
本来ならVuexをインストールしたりゴニョゴニョしないといけませんが、Nuxt.jsでVuexストアを使う場合は store ディレクトリ配下にファイルを配置することで管理ができます。

##storeディレクトリ配下にモジュールを配置する
ここでは ./store/todo.js として以下のファイルを作成するのですが、Nuxt.jsでは storeディレクトリ配下のパスがストアに名前空間を与えます。つまり **``todo`` という名前空間になります。**

```js:store/todo.js

export const state = () => ({
    list: []
});

export const mutations = {
    add(state, text) {
        state.list.push({
        text,
        done: false
        })
    },
    remove(state, { todo }) {
        state.list.splice(state.list.indexOf(todo), 1)
    },
    toggle(state, todo) {
        todo.done = !todo.done
    }
}
```

``state``の部分で変数(プロパティ)<font color="red">※vueファイルで言うところの``data(){ return { } }``の中</font>を定義します。
上の例では*配列のlist*ができています。

さらに``mutations``の中でstateの状態を変更させるメソッドを定義します。
では、次にどのようにして``.vue``から上の``state``を扱うか見てみましょう。
##componentからstateを呼び出す

```vue:pages/todo.vue

<template>
<div>
    <h1>TODOLIST</h1>
    <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input :checked="todo.done" @change="toggle(todo)" type="checkbox" />
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">remove</button>
    </li>
    <li>
      <input @keyup.enter="addTodo" placeholder="What needs to be done?" />
    </li>
  </ul>
</div>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
    computed: {
        todos() {
            return this.$store.state.todo.list
        }
    },
    methods: {
        addTodo(e) {
            this.$store.commit('todo/add', e.target.value)
            e.target.value = ''
        },
        ...mapMutations({
            toggle: 'todo/toggle'
        }),
        removeTodo(todo) {
            this.$store.commit('todo/remove', todo)
        }
    }
}
</script>

<style>
  .done {
    text-decoration: line-through;
  }
</style>
```
※ここではstate周りのことしか解説しません。
解説しやすいように``<script>``タグの部分を剥き出します。

```js

import { mapMutations } from 'vuex'

export default {
    computed: {
        todos() {
            return this.$store.state.todo.list
        }
    },
    methods: {
        addTodo(e) {
            this.$store.commit('todo/add', e.target.value)
            e.target.value = ''
        },
        ...mapMutations({
            toggle: 'todo/toggle'
        }),
        removeTodo(todo) {
            this.$store.commit('todo/remove', todo)
        }
    }
}
```

###storeに格納した値の取り出し方
上の例では、この部分で取得できます。

```js

this.$store.state.todo.list
```

つまり、``todo.js``で定義した``list``プロパティの値を指しています。

```js

export const state = () => ({
    list: []
});
```

###storeに値を格納する
上の例では、この部分で取得できます。

```js:todo.js

this.$store.commit('todo/add', e.target.value)
```

つまり、``todo.js``で定義した``todo/add``メソッドを入力された値を引数として実行してくださいと言うことです。

```js:todo.js

export const mutations = {
    add(state, text) {
        state.list.push({
        text,
        done: false
        })
    },

    //以下省略
}
```

#TIPS
##getters
要は、vuexのstateを取得する際のゲッターメソッドです。
基本的にstoreからの取得はゲッターメソッドを使って取得するので。上で作ったTODOリストのstateの取得をゲッターメソッドにします。
以下を``store/todo.js``に追加してください。

```js:todo.js

export const getters = {
    getList (state) {
        return state.list
    }
}
```
さらに``page/todo.vue``を下記のように変更してください。

```vue:todo.vue

<template>
<div>
    <h1>TODOLIST</h1>
    <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input :checked="todo.done" @change="toggle(todo)" type="checkbox" />
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">remove</button>
    </li>
    <li>
      <input @keyup.enter="addTodo" placeholder="What needs to be done?" />
    </li>
  </ul>
</div>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
    computed: {
        todos() {
            return this.$store.getters['todo/getList']
        }
    },
    methods: {
        addTodo(e) {
            this.$store.commit('todo/add', e.target.value)
            e.target.value = ''
        },
        ...mapMutations({
            toggle: 'todo/toggle'
        }),
        removeTodo(todo) {
            this.$store.commit('todo/remove', todo)
        }
    }
}
</script>

<style>
  .done {
    text-decoration: line-through;
  }
</style>
```
gettersを使うときはstoreでgetterメソッドを定義し**this.$store.getters['todo/getList']**で取得します。

##actions
最後にactionsを用いてTODOリストを行なっていきます。
*今回のTODOリストではactionsは特に必要ないですが、解説のためactions経由します。*
``todo.js``に以下を追加してください。

```js:store/todo.js

export const actions = {
    setList(vuexContext, text) {
        vuexContext.commit('add', text)
    },
    toggle(vuexContext, event) {
        vuexContext.commit('toggle', event)
    },
    remove(vuexContext, todo) {
        vuexContext.commit('remove', todo)
    }
}
```
最後に``todo.vue``も変更します。

```vue:pages/todo.vue

<template>
<div>
    <h1>TODOLIST</h1>
    <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input :checked="todo.done" @change="toggle(todo)" type="checkbox" />
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">remove</button>
    </li>
    <li>
      <input @keyup.enter="addTodo" placeholder="What needs to be done?" />
    </li>
  </ul>
</div>
</template>

<script>

export default {
    computed: {
        todos() {
            return this.$store.getters['todo/getList']
        }
    },
    methods: {
        addTodo(e) {
            this.$store.dispatch('todo/setList', e.target.value)
            e.target.value = ''
        },
        toggle(e) {
            this.$store.dispatch('todo/toggle', e)
        },
        removeTodo(todo) {
            this.$store.dispatch('todo/remove', todo)
        }
    }
}
</script>

<style>
  .done {
    text-decoration: line-through;
  }
</style>
```
``mutations``,``actions``の違いは非同期操作を行うときには``actions``に書くと言う認識で一先ずOKです。
#まとめ

- state: data保管庫
- getters: stateの情報を取得。別gettersの呼び出しも可能
- actions: storeの上書き以外の処理や非同期通信。別actionsの呼び出しも可能
- mutations: stateの上書き(代入)

**【基本の呼び出し方】**

- state: 直接呼び出すことはない
- getters: (return) this.$store.getters['*******']
- actions: this.$store.dispatch('*****')
- mutations: this.$store.commit('*******')

#参考にしたもの

- [参考1](https://ja.nuxtjs.org/guide/vuex-store/)
- [参考2](https://github.com/nuxt/nuxt.js/issues/848)
- [参考3](https://qiita.com/after666/items/7e94d61fed89406ae59a)

#最後に
以上が基本的なVuexの使い方です。
これを利用することでコードがすっきり書けpropsや$emitのバケツリレーなどが防げます。

もし間違い等アドバイスやご指摘があればご連絡お願いします。
次回はここでも実はちょいと出てきたのですがVuexヘルパーを解説していきます。