モジュール

単一ステートツリーを使うため、アプリケーションの全ての状態は、一つの大きなストアオブジェクトに内包されます。しかしながら、アプリケーションが大きくなるにつれて、ストアオブジェクトは膨れ上がってきます。

そのような場合に役立てるため Vuex ではストアをモジュールに分割できるようになっています。それぞれのモジュールは、モジュール自身の状態(state)、ミューテーション、アクション、ゲッター、モジュールさえも内包できます(モジュールをネストできます)- トップからボトムまでフラクタル構造です:

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 のステート

モジュールのローカルステート

モジュールのミューテーションやゲッターの中では、渡される第1引数はモジュールのローカルステートです。

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // state はモジュールのローカルステート
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

同様に、モジュールのアクションの中では context.state はローカルステートにアクセスでき、ルートのステートは context.rootState でアクセスできます:

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

また、モジュールのゲッターの中では、ルートのステートは第3引数でアクセスできます:

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

名前空間

デフォルトでは、アクション、ミューテーション、そしてゲッター内部のモジュールはグローバル名前空間の元で登録されます - これにより、複数のモジュールが同じミューテーション/アクションタイプに反応することができます。

モジュールをより自己完結型にまた再利用可能なものにしたい場合は、それを namespaced: true によって名前空間に分けることができます。モジュールが登録されると、そのゲッター、アクション、およびミューテーションのすべてが、モジュールが登録されているパスに基づいて自動的に名前空間に入れられます。例えば:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // モジュールのアセット
      state: { ... }, // モジュールステートはすでにネストされており、名前空間のオプションによって影響を受けません
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // ネストされたモジュール
      modules: {
        // 親モジュールから名前空間を継承する
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // さらに名前空間をネストする
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

名前空間のゲッターとアクションは、ローカライズされた gettersdispatchcommit を受け取ります。言い換えれば、同じモジュールに接頭辞 (prefix) を書き込まずに、モジュールアセットを使用することができます。名前空間オプションの切り替えは、モジュール内のコードには影響しません。

名前空間付きモジュールでのグローバルアセットへのアクセス

グローバルステートとゲッターを使いたい場合、rootStaterootGetters はゲッター関数の第3引数と第4引数として渡され、アクション関数に渡される context オブジェクトのプロパティとしても公開されます。

アクションをディスパッチするか、グローバル名前空間にミューテーションをコミットするには、dispatchcommit の3番目の引数として {root: true} を渡します。

modules: {
  foo: {
    namespaced: true,

    getters: {
      // `getters` はこのモジュールのゲッターにローカライズされています
      // ゲッターの第4引数経由で rootGetters を使うことができます
      someGetter (state, getters, rootState, rootGetters) {
        getters.someOtherGetter // -> 'foo/someOtherGetter'
        rootGetters.someOtherGetter // -> 'someOtherGetter'
      },
      someOtherGetter: state => { ... }
    },

    actions: {
      // ディスパッチとコミットもこのモジュール用にローカライズされています
      // ルートディスパッチ/コミットの `root` オプションを受け入れます
      someAction ({ dispatch, commit, getters, rootGetters }) {
        getters.someGetter // -> 'foo/someGetter'
        rootGetters.someGetter // -> 'someGetter'

        dispatch('someOtherAction') // -> 'foo/someOtherAction'
        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'

        commit('someMutation') // -> 'foo/someMutation'
        commit('someMutation', null, { root: true }) // -> 'someMutation'
      },
      someOtherAction (ctx, payload) { ... }
    }
  }
}

名前空間によるバインディングヘルパー

mapStatemapGettersmapActions、そして mapMutations ヘルパーを使って名前空間付きモジュールをコンポーネントにバインディングするとき、少し冗長になります:

computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  })
},
methods: {
  ...mapActions([
    'some/nested/module/foo',
    'some/nested/module/bar'
  ])
}

このような場合は、第1引数としてモジュールの名前空間文字列をヘルパーに渡すことで、そのモジュールをコンテキストとして使用してすべてのバインディングを行うことができます。上記は次のように単純化できます。

computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo',
    'bar'
  ])
}

プラグイン開発者向けの注意事項

モジュールを提供するプラグインを作成し、ユーザーがそれらを Vuex ストアに追加できるようにすると、モジュールの予測できない名前空間が気になるかもしれません。あなたのモジュールは、プラグインユーザーが名前空間付きモジュールの元にモジュールを追加すると、その名前空間に属するようになります。この状況に適応するには、プラグインオプションを使用して名前空間の値を受け取る必要があります。

// プラグインオプションで名前空間値を取得し、
// そして、Vuex プラグイン関数を返す
export function createPlugin (options = {}) {
  return function (store) {
    /// 名前空間をプラグインモジュールの型に追加する
    const namespace = options.namespace || ''
    store.dispatch(namespace + 'pluginAction')
  }
}

動的にモジュールを登録する

ストアが作られたstore.registerModule メソッドを使って、モジュールを登録できます:

// `myModule` モジュールを登録します
store.registerModule('myModule', {
  // ...
})

// ネストされた `nested/myModule` モジュールを登録します
store.registerModule(['nested', 'myModule'], {
  // ...
})

モジュールのステートには store.state.myModulestore.state.nested.myModule でアクセスします。

動的なモジュール登録があることで、他の Vue プラグインが、モジュールをアプリケーションのストアに付属させることで、状態の管理に Vuex を活用できることができます。例えば vuex-router-sync ライブラリは、動的に付属させたモジュール内部でアプリケーションのルーティングのステートを管理することで vue-router と vuex を統合しています。

store.unregisterModule(moduleName) を呼び出せば、動的に登録したモジュールを削除できます。ただしストア作成(store creation)の際に宣言された、静的なモジュールはこのメソッドで削除できないことに注意してください。

results matching ""

    No results matching ""