vuex--核心概念Module记录

441 阅读4分钟

Module

State,Action,Mutation,Getter学习较为简单,可以参考官网,Module较为复杂,所以记录,方便以后回顾。

由于使用单一状态,所有状态会集中一起。当应用变得非常复杂时,store 对象就会变得非常庞大且不好维护。所以为了解决这个问题,Module应运而生。

1.基本结构

可以将复杂的项目切成多个模块,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

const moduleA = {
  state:{name:"moduleAName"}  
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state:{name:"moduleBName"} 
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  state:{name:"rootName"}  
  modules: {
    a: moduleA,
    b: moduleB
  }
})
2.各部分参数以及可以取到的值
(1)getters参数及其可取到的值
  1. state:获取modules中的state数据
  2. getters:获取modules中的getters数据
  3. rootState:获取根部state数据
  4. rootGetters:获取根部getters数据

image.png

(2)mutations参数及其可取到的值
  1. state:获取modules中的state数据
  2. 调用方法时传入的值

image.png

(3)mutations参数及其可取到的值
  1. state:获取modules中的state数据

  2. getters:获取modules中的getters数据

  3. rootState:获取根部state数据

  4. rootGetters:获取根部getters数据

  5. commit:可以调用自身模块的mutations里面的方法,还可以加第三个参数{root:true},这样可以调用根部mutations里面的方法。 image.png

  6. dispatch:可以调用自身模块的actions里面的方法,还可以加第三个参数{root:true},这样可以调用根部actions里面的方法。 image.png

3.命名空间

命名空间的产生是为了避免不同的模块使用相同名字的getter、mutation和action。使用namespaced: true来声明空间。使用命名空间对getter、mutation和action的调用产生影响。

const store = createStore({
  modules: {
    account: {
      namespaced: true,
      // 模块内容(module assets)
      state: () => ({ ... }), // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
      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']
          }
        }
      }
    }
  }
})
4.带命名空间的模块注册全局 action

在模块内部可以使用root: true注册全局命名空间的

my.vue

image.png root.js

image.png

moduleA.js

image.png

5.带命名空间的绑定函数

为了方便使用定义好的模块内容,使用 mapStatemapGettersmapActions 和 mapMutations,可以分别放在computed或者methods里面。

         ...mapState('moduleName',{
            moduleAName:'stateName'
        }),
        ...mapGetters('moduleName',{
            getterName:'getterName'
        })
        ...mapActions('moduleName', [
            'moduleActionName',
        ])
        ...mapMutations('moduleName', [
            'moduleMutationName',
        ]),

还可以通过使用 createNamespacedHelpers 这个辅助函数创建基于某个命名空间的内容

import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('moduleName')
export default {
  computed: {
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}
6.模块动态注册
import { createStore } from 'vuex'
const store = createStore({})
// 注册模块 `myModuleName`
store.registerModule('myModuleName', {})
// 注册嵌套模块 `nested/myModuleName`
store.registerModule(['nested', 'myModuleName'], {})

可以使用 store.unregisterModule(moduleName) 来动态卸载模块。注意不能使用此方法卸载静态模块(即创建 store 时声明的模块)。

可以通过 store.hasModule(moduleName) 方法检查该模块是否已经被注册到 store。需要记住的是,嵌套模块应该以数组形式传递给 registerModule 和 hasModule,而不是以路径字符串的形式传递给 module。

模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。

注册新模块的时候如何保留原来的State

action、mutation 和 getter 会被添加到 store 中。通过preserveState: true来保留原来的state。举例如下:

const store = createStore({
 modules: {
        a: moduleA,
        b: moduleB
    }
})
//使用preserveState: true
store.registerModule("c", moduleB, { preserveState: true });

image.png

//没有使用preserveState: true
store.registerModule("c", moduleB);

image.png

7.模块重用

当项目很大的时候,可能会有很多相似的模块,那么此时可以将公共的部分提取出来。但是如果不做处理直接使用的话,那么会产生变量污染。

//模块a和模块c都是用的moduleA
import moduleA from './moduleA/index'
const store = createStore({
    state: {
        rootName: 'this is the rootName'
    },
    modules: {
        a: moduleA,
        b: moduleB
    },
    mutations: {
        changeRootName(state, paylaod) {
            state.rootName = paylaod
        },
    },
    actions: {
        test({ commit, state, getters, dispatch, rootState, rootGetters }, payload) {
            commit('edit', "This is a new root name ")
        },
    }
    // plugins:[saveChangeName]
})
store.registerModule("c", moduleA);

通过vue-devtools查看结果

image.png

点击按钮之后结果如下,可以发现都变化了。

image.png

通过如下方式:可以隔绝掉相互之间的影响,从而回归正常。

const moduleA = {
    namespaced: true,
    state() {
        return { 
            name: 'My moduleA name is moduleA' 
        }
    }
}
export default moduleA

image.png