Using registerModule to register the same module more than once will cause subsequent calls to actions under the same module to fire more than once

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

/ / root module
const store = new Vuex.Store({});

// Submodule - just define actions for simplicity
const moduleA = {
  actions: {
    inc() {
      console.log("i was called"); ,}}};// Register submodules multiple times
store.registerModule("moduleA", moduleA);
store.registerModule("moduleA", moduleA);

// Call an action
store.dispatch("inc");
Copy the code

The action is actually executed twice

i was called
i was called
Copy the code

The reason for this problem is that vuex does not check whether the module itself is registered or not. Actions are collected internally through arrays. This causes actions to be added to the array multiple times when the same module is registered multiple times. Action is registered in vuEX with the following simplified code:

module.forEachAction((action, key) = > {
  const type = action.root ? key : namespace + key;
  const handler = action.handler || action;
  registerAction(store, type, handler, local);
});

function registerAction(store, type, handler, local) {
  const entry = store._actions[type] || (store._actions[type] = []);
  entry.push(function wrappedActionHandler(payload) {
    // action parameter injection logic}}Copy the code

The reason why the action is an array is that the author considers that different modules may need to respond to an action. That is to say, by default, the actions of different modules can have the same name and are registered in the root namespace by default. For example, we have an application where different pages are divided into different modules, and when users switch accounts, we need to refresh all resources displayed on different pages. In this case, we can register an action named refreshResource, and each module can implement its own customized refresh logic. The refresh is then triggered all at once (mutation is also registered under the root namespace by default). Of course, you can also add a Namespaced attribute to your Module to keep Vuex from registering actions in the root namespace.

Modules that have the Namespaced attribute can register action and mutation in the root namespace by adding the root attribute to their actions

const moduleA = {
  namespaced: true.actions: {
    foo: {
      root: true.handler(namespacedContext, payload) {
        // ...}},}};Copy the code

So how do we avoid the problem of module double registration? The idea is actually quite simple, that is, before we register the module to determine whether the module has been registered, if it has been registered no longer registered

const store = new Vuex.Store({
  // ...
});
rewriteRegisterModule(store);

function rewriteRegisterModule(store) {
  const original = store.registerModule;
  store.registerModule = function(path, ... rest) {
    if (store.hasModule(path)) {
      return; } original.call(store, path, ... rest); }; }Copy the code