从两个页面上的组件注册的相同VueX存储模块

问题描述

使用VueX和Vue-Router时遇到了一个奇怪的情况,我不太确定如何彻底解决它。

我有一个组件(我们将其称为“ ComponentWithStore”)注册一个命名商店模块,如下所示:(商店的实际内容无关紧要。显然,在使用VueX的此玩具示例中,这是过分的,但这是更为复杂的应用程序的非常简化的版本,在其中使用VueX有意义)

// ComponentWithStore.vue
<script>
import module from './componentStore.js';

export default {
    name: 'ComponentWithStore',beforeCreate() {
        this.$store.registerModule(module.name,module);
    },beforeDestroy() {
        this.$store.unregisterModule(module.name);
    }
}
</script>

然后,我将该组件放置在一个视图(或页面)中,该视图(或页面)随后与路线相关联(我们称此页面为“首页”)。

// Home.vue
<template>
  <div class="home">
    Home
    <ComponentWithStore/>
  </div>
</template>

<script>
import ComponentWithStore from '@/components/ComponentWithStore.vue';

export default {
  name: "Home",components: { ComponentWithStore }
};
</script>

到目前为止,当我访问本地路线时,商店模块已注册,而当我离开本地路线时,商店模块已清理。

假设我然后创建一个新视图(页面),我们将其称为“关于”,这个新的“关于”页面与Home.vue基本上相同,因为它也使用了ComponentWithStore。

// About.vue
<template>
  <div class="about">
    About
    <ComponentWithStore/>
  </div>
</template>

<script>
import ComponentWithStore from '@/components/ComponentWithStore.vue';

export default {
  name: "About",components: { ComponentWithStore }
};
</script>

现在,从首页导航到“关于”时遇到以下错误

vuex.esm.js?2f62:709 [vuex] duplicate namespace myComponentStore/ for the namespaced module myComponentStore

发生的情况是,在“关于”的存储模块未注册之前,在“ ”注册了“ Home”存储模块,因此出现重复的命名空间错误

因此,我很好地理解了问题所在,但是我不确定哪种解决方案可以解决此问题。欢迎所有想法

可以在此处找到完整的示例:https://github.com/mmgagnon/vue-module-router-clash 要使用它,只需运行它并在“主页”和“关于”页面之间切换。

解决方法

正如您所提到的,问题是由于钩子的顺序引起的。您只需要使用正确的钩子,以确保在新组件再次注册之前,旧组件首先注销了模块。

从高层次上讲,这是您从首页导航到“关于”时情况的钩子顺序:

  1. 关于beforeCreate
  2. 关于创建的
  3. 毁灭前的家
  4. 房屋被毁
  5. 关于已安装

因此,您可以在mounted钩中注册该模块,然后在beforeDestroydestroyed中注销该模块。

我还没有测试过。如果您的组件在创建之后和挂载之前需要访问存储,则可能不起作用。


一种更好的方法是创建一个抽象来注册和取消注册允许重叠的模块。

未经测试,但类似的方法可能有效:

function RegistrationPlugin(store) {
  const modules = new Map()

  store.registerModuleSafely = function (name,module) {
    const count = modules.get(name) || 0

    if (count === 0) {
      store.registerModule(name,module)
    }

    modules.set(name,count + 1)
  }

  store.unregisterModuleSafely = function (name) {
    const count = modules.get(name) || 0

    if (count === 1) {
      store.unregisterModule(name)
      modules.delete(name)
    } else if (count > 1) {
      modules.set(name,count - 1)
    }
  }
}

在创建商店时指定插件:

const store = new Vuex.Store({
  plugins: [RegistrationPlugin]
})

现在像这样注册和注销模块:

beforeCreate() {
  this.$store.registerModuleSafely(module.name,module)
},destroyed() {
  this.$store.unregisterModuleSafely(module.name)
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...