Vuex ストア

状態を管理してくれる Vuex ストアは、あらゆる大規模アプリケーションにとても役に立ちます。Nuxt.js が Vuex をコアに組み入れたのはそのような理由からです。

ストアを有効にする

Nuxt.js は store ディレクトが存在するときにはそちらを探索します:

  1. Vuex をインポートします
  2. vuex モジュールを vendor のバンドルファイルに追加します
  3. store オプションをルートの Vue インスタンスに追加します

Nuxt.js では 2つのモードのストア があります。どちらか好みのほうを選んで使ってください:

  • クラシックモード: store/index.js がストアインスタンスを返します
  • モジュールモード: store ディレクトリ内のすべての *.js ファイルが モジュール に変換されます(index はルートモジュールとして存在します)

クラシックモード

ストアをクラシックモードで有効にするには store/index.js ファイルを作成し、ストアインスタンスをエクスポートします:

import Vuex from 'vuex'

const store = () => new Vuex.Store({

  state: {
    counter: 0
  },
  mutations: {
    increment (state) {
      state.counter++
    }
  }
})

export default store

vuex は Nuxt.js によって取り込まれているため、別途インストールする必要はありません。

クラシックモードを有効にすると、コンポーネント内で this.$store を使うことができます:

<template>
  <button @click="$store.commit('increment')">{{ $store.state.counter }}</button>
</template>

モジュールモード

Nuxt.js では store ディレクトリ内にモジュールと対応するファイルを持つことができます。

このオプションを使いたいときは、ストアインスタンスの代わりに、store/index.js 内でストア、ミューテーション、アクションをエクスポートします:

export const state = {
  counter: 0
}

export const mutations = {
  increment (state) {
    state.counter++
  }
}

また、次のような store/todos.js ファイルを作成できます:

export const state = {
  list: []
}

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

ストアは下記のようになります:

new Vuex.Store({
  state: { counter: 0 },
  mutations: {
    increment (state) {
      state.counter++
    }
  },
  modules: {
    todos: {
      state: {
        list: []
      },
      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
        }
      }
    }
  }
})

そして pages/todos.vue 内で todos モジュールを下記のように使うことができます:

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

<script>
import { mapMutations } from 'vuex'

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

<style>
.done {
  text-decoration: line-through;
}
</style>
ストアインスタンスをエクスポートすることでモジュールを持つこともできます。その際にはモジュールをストアに手動で追加する必要があります。

fetch メソッド

fetch メソッドは、ページがレンダリングされる前に、データをストアに入れるために使われます。コンポーネントのデータをセットしないという点を除いては data メソッドとよく似ています。

fetch メソッドについてより深く理解するためには ページの fetch メソッド API を参照してください。

nuxtServerInit アクション

nuxtServerInit というアクションがストア内に定義されているときは、Nuxt.js はそれをコンテキストとともに呼び出します(ただしサーバーサイドに限ります)。サーバーサイドからクライアントサイドに直接渡したいデータがあるときに便利です。

例えば、サーバーサイドでセッションを持っていて、接続しているユーザーに req.session.user を通じてアクセスできるとします。認証されたユーザーにストアを渡すために store/index.js 下記のように書き換えます:

actions: {
  nuxtServerInit ({ commit }, { req }) {
    if (req.session.user) {
      commit('user', req.session.user)
    }
  }
}

Vuex ストアの モジュール モードを使っている場合はなら、プライマリモジュール(store/index.js)のみ、このアクションを受け取ることができます。その他のモジュールのアクションでも使いたい場合は、プライマリモジュールからチェインする必要があります。

コンテキストは nuxtServerInit へ第二引数として渡されます。context.redirect()context.error() が除外される点を除いては data メソッドや fetch メソッドと共通しています。

注意: 非同期の nuxtServerInit アクションは nuxt サーバーの待機を可能にするために Promise を返さなければなりません

間違いを見つけた、またはドキュメントに貢献したいですか? GitHub でこのページを編集する