Vuexのmoduleのstateを呼ぶ時store.modules.◯◯.stateにならない理由

Vuexにはモジュールという機能があり、コンポーネントが複雑化して大きな一つのstoreにstateを管理するには難しくなった時のために、モジュールという単位で分けることで管理をすることが出来ます。

以下はmoduleの例です。Vuexのドキュメントに載っているものの写しです。
https://vuex.vuejs.org/ja/guide/modules.html

```modules.js
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> `moduleA` のステート
store.state.b // -> `moduleB` のステート
```

moduleAとmoduleBはどちらもstateとmutationsを持っており、`new Vuex.Store`でインスタンス化したオブジェクトをstore変数に入れています。その時modulesプロパティの中でmoduleAをa、moduleBをbというプロパティにセットしています。

ここで疑問が浮かんだのですが、moduleA内のstateにアクセスする時は`store.state.a`となります。「aの中のstate」を呼んでいるのに「stateの中からaを呼んでいる」ので、直感的には`store.modules.a.state`ではないかと思いました。しかし`store.state.a`は間違っていません。

理由を探るためVuexのソースを見てみました。結論から言うと、**Storeクラス内にモジュール内のstateとは全く別のstateというオブジェクト**を作り、モジュール内のstateを**代入して置き換え**ています。

詳しくVuexのコードを見てみます。上のコードの`store`変数は`new Vuex.Store`で作ったオブジェクトなので、Storeクラスの中に`state`オブジェクトがありそうです。

Storeクラスはsrc/store.jsに定義されていました。
https://github.com/vuejs/vuex/blob/dev/src/store.js
stateは以下のように定義されていました。関係のある部分だけまとめています。

```src/store.js
import ModuleCollection from './module/module-collection'

export class Store {
  constructor(options = {}) {
    this._modules = new ModuleCollection(options)
    const state = this._modules.root.state
  }
}
```
https://github.com/vuejs/vuex/blob/ba2ff3a3de394a4c5c9a72ed7314ad3bb52f6a53/src/store.js#L53

Storeクラスのstate変数に`this._modules.root.state`が入っています。これが一番上の例でいう`store.state`に該当します。

Storeをインスタンス化する時引数に入ったオブジェクトを`options`に入れています。このoptionsが一番上の例の`{modules: {a: moduleA, b: moduleB}}`の部分となります。
optiosを引数に入れた`ModuleCollection`クラスを初期化して`_modules`に入れ、中の`root.state`を取り出しているようです。

ここで注意するべきは**store.jsの中に`modules`という変数はありません**。したがって`store.modules.state.a`と書いてしまうとstore.modulesがundefinedであるためにエラーになります。

では`store.state`にセットしている`root`は何なのか、moduleAとmoduleBはどのように取り出しているのかさらに掘り下げるためにModuleCollectionクラスを見てみます。こちらも関係ある部分だけを抜粋しました。
https://github.com/vuejs/vuex/blob/dev/src/module/module-collection.js

```src/module/module-collection.js

import Module from './module'
import { forEachValue } from '../util'

export default class ModuleCollection {
  constructor (rawRootModule) {
    // register root module (Vuex.Store options)
    this.register([], rawRootModule, false)
  } 

  register (path, rawModule, runtime = true) {
    if (process.env.NODE_ENV !== 'production') {
      assertRawModule(path, rawModule)
    }
    const newModule = new Module(rawModule, runtime)
    if (path.length === 0) {
      this.root = newModule
    } else {
      const parent = this.get(path.slice(0, -1))
      parent.addChild(path[path.length - 1], newModule)
    }

    // register nested modules
    if (rawModule.modules) {
      forEachValue(rawModule.modules, (rawChildModule, key) => {
        this.register(path.concat(key), rawChildModule, runtime)
      })
  }
}
```

`ModuleCollection`をnewするときに引数に`new Vuex.Store`の引数と同じものを入れており、それを使って`register`関数を実行しています。
register関数内で`Module`クラスをnewしており、`this.root`に代入しています。これが先ほどstore.jsでみた`this._modules.root`となります。

もしmodulesがあれば下の方の`if(rawModule.modules)`の中身が通るため、中のオブジェクトループで回して再帰でregister関数を実行しているようです。この`rawChildModule`に上の例でいう`moduleA`、`moduleB`が入ってきます。

newしているModuleクラスのコンストラクタもみてみます。
https://github.com/vuejs/vuex/blob/dev/src/module/module.js

```src/module/module.js
export default class Module {
  constructor (rawModule, runtime) {
    this.runtime = runtime
    // Store some children item
    this._children = Object.create(null)
    // Store the origin module object which passed by programmer
    this._rawModule = rawModule
    const rawState = rawModule.state

    // Store the origin module's state
    this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
  }
}
```

このrawModuleには上の例でいうmoduleA、moduleBが入るため、その中のstateを新たにthis.stateに代入しているようです。これで`store.state`の中に各モジュール内のstateの中身を移すことが出来ました。