问题描述
使用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 要使用它,只需运行它并在“主页”和“关于”页面之间切换。
解决方法
正如您所提到的,问题是由于钩子的顺序引起的。您只需要使用正确的钩子,以确保在新组件再次注册之前,旧组件首先注销了模块。
从高层次上讲,这是您从首页导航到“关于”时情况的钩子顺序:
- 关于beforeCreate
- 关于创建的
- 毁灭前的家
- 房屋被毁
- 关于已安装
因此,您可以在mounted
钩中注册该模块,然后在beforeDestroy
或destroyed
中注销该模块。
我还没有测试过。如果您的组件在创建之后和挂载之前需要访问存储,则可能不起作用。
一种更好的方法是创建一个抽象来注册和取消注册允许重叠的模块。
未经测试,但类似的方法可能有效:
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)
}