はじめに
Nuxt.jsのVuexモジュールモードで、store以下のファイルが増えてきて整理したくなりました。
いざディレクトリを切ってファイルを整理し始めると、stateやactionへのアクセス仕方で少し手間取ったので...
今回は、store配下でディレクトリを切った時、名前空間の違うvuexモジュールやVueコンポーネントからVuexのモジュールにアクセスする方法を備忘録的にまめておきます。
store内の構成
例として以下のようなディレクトリ構成下で説明して行きます。(コードの中身に意味はないでスルーしてください)
ちなみにNuxt.jsではstore/index.js
がストアインスタンスを返さない時、モジュールモードになります。詳しくはこちら。
store/
┣ shared/
┣ auth.js
┣ pages/
┣ mypage.js
pages/
┣ mypage/
┣ index.vue
export const state = () => ({
token: null
})
export const mutations = {
setToken(state, token) {
state.token = token
}
}
export const actions = {
setToken({ commit }, token) {
commit('setToken', token)
},
deleteToken({ commit }) {
commit('setToken', null)
}
}
export const state = () => ({
name: ''
})
export const mutations = {
setName(state, name) {
state.name = name
}
}
export const actions = {
login({ dispatch }, name) {
dispatch('setName', name)
dispatch('shared/auth/setToken', 'dummy', { root: true })
},
logout({ dispatch }) {
dispatch('setName', '')
dispatch('shared/auth/deleteToken', null, { root: true })
},
setName({ commit }, name) {
commit('setName', name)
}
}
<template>
<section>
<p>{{ name }}</p>
<p>{{ this.$store.state.pages.mypage.name }}</p>
<p @click="login('Alis')">login</p>
<p @click="logout">logout</p>
</section>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState('pages/mypage', ['name'])
},
methods: {
...mapActions('pages/mypage/', [
'login',
'logout'
])
}
}
</script>
では細かく見ていきましょう。
名前空間の違うVuexモジュールにアクセスする
今回の例で言うとstore/pages/mypage.js
からstore/models/auth.js
を参照したい時は以下のような形でauthモジュールのアクションを呼び出せます。
dispatch('shared/auth/setToken', 'dummy', { root: true })
dispatch('shared/auth/deleteToken', null, { root: true })
ここで2つのミソがあります。
1つ目はモジュール内は相対パス扱いなので{ root => true }
を第3引数のオプションに渡さないとpages/mypage/shared/auth/...
を参照しに行ってエラーになります。
2つ目はshared/auth/deleteToken
のように引数を受け取らないactionを呼ぶ場合は第2引数をnull埋めしないと{ root => true }
が効かずactionが呼ばれません。
これはエラーにならないので意外と気づかないです...
ComponentからVuexモジュールにアクセスする
stateの参照
stateにアクセスする時は直接参照するか、バインディングヘルパーを使う方法があります。
直接参照は$storeオブジェクトを掘っていくことで参照できます。
this.$store.state.pages.mypage.name
バインディングヘルパーを使う場合は...mapState
を使い、storeからの相対パスでnamespaceを指定します。
<template>
<p>{{ name }}</p>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState('pages/mypage', ['name'])
}
}
ちなみにayncdata()
からはcontextにstoreオブジェクトがあるのでそれを使って参照出来ます。
asyncData({ store }) {
store.state.shared.auth.token
}
アクションの参照
アクションもバイディングヘルパーを使えばstateと同じように参照できます。
ちなみにバインディングヘルパーは以下のような感じで複数のvuexモジュールを指定する事も出来ます。
<template>
<div>
<p @click="login('Alis')">login</p>
<p @click="deleteToken">logout</p>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('pages/mypage', [
'login'
])
...mapActions('shared/auth', [
'deleteToken'
])
}
バリンティングヘルパーを使わない場合は以下の通りです。
export default {
methods: {
logout() {
this.$store.dispatch('pages/mypage/logout')
}
}
}
まとめ
これでstore以下をディレクトリ切って整理出来ました。