30
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

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

はじめに

おはようございます。こんにちは。こんばんは。
Watatakuです。
今回は以前こちらで書かせていただいた内容の中で「次回Vuexやるよー」と言っておきながらやっていなかったのでやっていきます。

Vuexとは

Vuex は複数のコンポーネント間で状態を共有するために使われる状態管理のライブラリです。
Vueのコンポーネントから状態管理の部分をVuex側に寄せることで、コンポーネント間のプロパティ渡しの連鎖による複雑さを回避できます。

使い方

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

storeディレクトリ配下にモジュールを配置する

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

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の部分で変数(プロパティ)※vueファイルで言うところのdata(){ return { } }の中を定義します。
上の例では配列のlistができています。

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

componentからstateを呼び出す

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>タグの部分を剥き出します。


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に格納した値の取り出し方

上の例では、この部分で取得できます。


this.$store.state.todo.list

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


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

storeに値を格納する

上の例では、この部分で取得できます。

todo.js

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

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

todo.js

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

    //以下省略
}

TIPS

getters

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

todo.js

export const getters = {
    getList (state) {
        return state.list
    }
}

さらにpage/todo.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に以下を追加してください。

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も変更します。

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('*******')

参考にしたもの

最後に

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
30
Help us understand the problem. What are the problem?