preface

Last time, I published vuex study notes, and it was mentioned in the comment section whether vuex modularization was involved. I searched online and learned about it, and then I will share it with you

Positive start

Vuex uses a single state tree, where all the states of an application are grouped into one large object. When the application becomes very complex, the Store object can become quite bloated.

To solve these problems, Vuex allows us to split the Store into modules. Each module has its own state, mutation, action, getter, and even nested submodules — split from top to bottom in the same way. Today we’ll take a brief look at its use

1. File structure

File structure, modular use of a modules folder, which contains the module’s JS file/module name folder.

The official standard here is one JS file per module, but if the module is too complex, you can split the code inside.

/ / store folder │ actions. Js │ getters. Js │ index. The js │ mutations. Js │ state. The js │ └ ─ modules │ moduleB. Js │ └ ─ moduleA index.js mutation.js state.jsCopy the code

Then import these modules in the js file that creates the store, directly

import moduleA from './modules/moduleA/index'
import moduleB from './modules/moduleB';

export default new Vuex.Store({
    state,
    getters,
    mutations,
    actions,
    modules: {
        moduleA,
        moduleB,
    }
});
Copy the code

2. Definition of local state object of module

Getters, mutations, and actions in the module will receive different values from the root state.

getter

In the getter, it takes three parameters, the first is the state in the module, the second is the getters in the module, and the third is the rootState,

const getters = {
  bFullName: (state, getters, rootState) => `full${state.bName}`
}
Copy the code

mutation

The first argument passed to the mutation callback is also the state in the module, otherwise the same as when the root state was defined

Const mutations = {SET_B_NAME(state, payload) {debugger state.bname = paypay.name; }}Copy the code

action

For the last action, it still only passes in the context object, and then the state property in this object refers to the state in the module, and the rootState refers to the rootState, as follows

const actions = {
  ASYNC_SET_NAME({ state, commit, rootState }, payload) {
    setTimeout(() => {
      state.bName = 'asyncName'
    }, 4000)
  }
}
Copy the code

3 the use of

3.1 the state gets

The state name must be preceded by the module name before it can be placed into the object in the module. Specific as follows

/ / add a module name this. On the basis of the original $store. State. ModuleB. BName; // The same goes for the auxiliary function Deno... mapState({ name: state => state.moduleB.bName, })Copy the code

3.2 Namespaces

Getters, mutations, and actions are all registered in the global namespace by default, so we can use them in the same way as the root state by default. However, we can use them in the same way as the root state by default. True makes it a module with namespaces. When a module is registered, all its getters, actions, and mutations are automatically named according to the path the module was registered with.

// For moduleB, add namespaced: true, export default {namespaced: true, state, getters, mutations, actions,}Copy the code
3.2.1 Use of auxiliary functions

Because of the namespace layer, we use helper functions with an extra layer of module names, see the code below.

// getter this.$store.getters['moduleB/bFullName']; . mapGetters({ bGetter2: 'moduleB/bFullName' }) // mutation this.$store.commit('moduleB/SET_B_NAME', { name: 'QQ' }); . mapMutations({ setBname: 'moduleB/SET_B_NAME' }), // action this.$store.dispatch('moduleB/ASYNC_SET_NAME', { name: "JJ" }); . mapActions({ aSetAge: 'moduleB/ASYNC_SET_NAME', }),Copy the code

It’s annoying to write the module name every time, so these helper functions give us an argument bit to bind to the namespace.

// bName in the moduleB module... MapState ('moduleB', {name: state => state.bname}) mapAction('moduleB',[ '/ASYNC_SET_NAME' ])Copy the code

CreateNamespacedHelpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers helpers

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('moduleB') // moduleName
Copy the code

Once created, we can ask about the status of the module using the previous notation.

. mapState({ bName: state => state.bName, }),Copy the code
3.2.2 Accessing global content in a module with namespaces

If you want to use global state and getter, rootState and rootGetter are passed to the getter as the third and fourth arguments, as well as to the action through the properties of the Context object.

To distribute action or commit mutation within the global namespace, pass {root: true} as the third argument to Dispatch or COMMIT. Take a look at the following code:

modules: { foo: { namespaced: true, getters: {// In the getter of this module, 'getters' is localized // You can call' rootGetters' someGetter (state, getters, rootState, RootGetters) {getters. SomeOtherGetter / / - > 'foo/someOtherGetter module getter rootGetters. SomeOtherGetter / / - > 'someOtherGetter global getter'}, someOtherGetter: state => {... } }, actions: {// In this module, // They can accept the 'root' attribute to access the root dispatch or commit someAction ({dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter' rootGetters.someGetter // -> 'someGetter' Dispatch ('someOtherAction') // -> 'foo/someOtherAction' action dispatch('someOtherAction', null, {root: True}) // ->'someOtherAction' global action commit('someMutation') // ->' foo/someMutation' module action Commit ('someMutation', NULL, {root: true}) // -> 'someMutation' global mutation}, someOtherAction (CTX, payload) {... }}}}Copy the code
3.3.3 Register actions in the module as global

When we want an action in our module to be promoted to a global action, add root when it is declared: True, and put the action definition in the hanler function as follows:

// Action [ASET_AGE]({commit}, payload) {setTimeout(() => {commit('SET_B_NAME', payload.name); }, 2000)}, // upgrade to globalAction globalAction: {root: true, handler({ commit }, payload) { debugger setTimeout(() => { commit('SET_B_NAME', payload.name); }, 2000)}}}Copy the code