【Nuxt.js】VuexモジュールモードでStore以下のファイル群を整理する時のあれこれ

# はじめに
Nuxt.jsのVuexモジュールモードで、store以下のファイルが増えてきて整理したくなりました。
いざディレクトリを切ってファイルを整理し始めると、stateやactionへのアクセス仕方で少し手間取ったので...

今回は、store配下でディレクトリを切った時、名前空間の違うvuexモジュールやVueコンポーネントからVuexのモジュールにアクセスする方法を備忘録的にまめておきます。

## store内の構成
例として以下のようなディレクトリ構成下で説明して行きます。（*コードの中身に意味はないでスルーしてください*）
*ちなみにNuxt.jsでは`store/index.js`がストアインスタンスを返さない時、モジュールモードになります。詳しくは[こちら](https://ja.nuxtjs.org/guide/vuex-store/)。*

```bash
store/
  ┣ shared/
    ┣ auth.js
  ┣ pages/
    ┣ mypage.js
pages/
  ┣ mypage/
    ┣ index.vue
```
 
```js:store/models/auth.js
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)
  }
}
```

```js:store/pages/mypage.js
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)
  }
}
```

```vue:pages/mypage/index.vue
<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モジュールのアクションを呼び出せます。

```js
dispatch('shared/auth/setToken', 'dummy', { root: true })
dispatch('shared/auth/deleteToken', null, { root: true })
```

ここで２つのミソがあります。

１つ目はモジュール内は相対パス扱いなので`{ root => true }`を**第３引数**のオプションに渡さないと`pages/mypage/shared/auth/...`を参照しに行ってエラーになります。

２つ目は`shared/auth/deleteToken`のように引数を受け取らないactionを呼ぶ場合は第２引数を**null**埋めしないと`{ root => true }`が効かずactionが呼ばれません。
*これはエラーにならないので意外と気づかないです...*

## ComponentからVuexモジュールにアクセスする
### stateの参照
stateにアクセスする時は直接参照するか、バインディングヘルパーを使う方法があります。

直接参照は$storeオブジェクトを掘っていくことで参照できます。

```js
this.$store.state.pages.mypage.name
```
バインディングヘルパーを使う場合は`...mapState`を使い、storeからの相対パスでnamespaceを指定します。

```vue
<template>
　<p>{{ name }}</p>
</template>

<script>
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState('pages/mypage', ['name'])
  }
}
```

ちなみに`ayncdata()`からはcontextにstoreオブジェクトがあるのでそれを使って参照出来ます。

```js
asyncData({ store }) {
  store.state.shared.auth.token
}
```

### アクションの参照
アクションもバイディングヘルパーを使えばstateと同じように参照できます。
ちなみにバインディングヘルパーは以下のような感じで複数のvuexモジュールを指定する事も出来ます。

```vue
<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'
    ])
  }
```

バリンティングヘルパーを使わない場合は以下の通りです。

```js
export default {
  methods: {
    logout() {
       this.$store.dispatch('pages/mypage/logout')
     }
  }
}
```



# まとめ

これでstore以下をディレクトリ切って整理出来ました。