Reputation: 4808
I have a simple root App
which includes two different components Room
and Machine
. And each of these components include one component Datatable
which is totally same for both of them. To switch between Room
and Machine
I'm using dynamic components mechanism, nothing special. When component is changing then I just emit event and component Datatable
should log it in console with current module name. The problem is that each time I change component, event is sent multi times. If I understand right, after changing component the old one should be destroyed and the new one created so why this is happening? I'm using Vue.js v.2.4.1
Here is screenshot from console when I switch between components:
Here are components:
App.vue:
<template>
<div id="app">
<select style="padding: 10px" v-model="currentModule" @change="changeComponent">
<option value="Room">Room</option>
<option value="Machine">Machine</option>
</select>
<component :is="currentModule"></component>
</div>
</template>
<script>
import Room from './Room.vue';
import Machine from './Machine.vue';
export default {
name: 'app',
components: {
Room,
Machine
},
data () {
return {
currentModule: 'Room'
}
},
methods: {
changeComponent: function() {
Event.$emit('moduleHasChanged', this.currentModule)
}
},
}
</script>
Machine.vue:
<template>
<div>
Machine template
<datatable></datatable>
</div>
</template>
<script>
import Datatable from './Datatable.vue';
export default {
components: {
Datatable
}
}
</script>
Room.vue:
<template>
<div>
Room template
<datatable></datatable>
</div>
</template>
<script>
import Datatable from './Datatable.vue';
export default {
components: {
Datatable
}
}
</script>
Datatable.vue
<template>
<div>
Datatable
</div>
</template>
<script>
export default {
created() {
Event.$on('moduleHasChanged', (currentModule) => {
console.log(currentModule);
})
}
}
</script>
Upvotes: 1
Views: 2684
Reputation: 82459
This is happening because you are continually adding event listeners (when the Datatable
component is created) and never removing them. Vue typically handles this for you, but since you are using an event bus you need to do it yourself.
Simply add a beforeDestroy
handler and remove the event handler.
console.clear()
const Event = new Vue()
const Datatable = {
template: `
<div>
Datatable
</div>
`,
methods: {
moduleChanged(currentModule) {
console.log(currentModule);
}
},
created() {
Event.$on('moduleHasChanged', this.moduleChanged)
},
beforeDestroy() {
Event.$off('moduleHasChanged', this.moduleChanged)
}
}
const Room = {
template: `
<div>
Room template
<datatable></datatable>
</div>
`,
components: {
Datatable
}
}
const Machine = {
template: `
<div>
Machine template
<datatable></datatable>
</div>
`,
components: {
Datatable
}
}
const App = {
name: 'app',
template: `
<div id="app">
<select style="padding: 10px" v-model="currentModule" @change="changeComponent">
<option value="Room">Room</option>
<option value="Machine">Machine</option>
</select>
<component :is="currentModule"></component>
</div>
`,
components: {
Room,
Machine
},
data() {
return {
currentModule: 'Room'
}
},
methods: {
changeComponent: function() {
Event.$emit('moduleHasChanged', this.currentModule)
}
},
}
new Vue({
el: "#app",
render: h => h(App)
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
</div>
Upvotes: 1