I'm using vue-router for switching pages. Now I have two Vue documents:
In both .vue pages I'm using the mounted()
instance. In Page1.vue the code starts listening to a socket connection. When I switch to Page2 and back to Page1, it starts listening twice to the socket connection.
I've tested with a simple console.log('Page1.vue') and Page2.vue in page2. When I switch pages, it will console.log multiple times, for each time I switch a page, it will do an extra console.log.
I tried to only execute the code in mounted()
instance once, but after switching pages, it doesn't do anything.
How can I take care it only mounts once, or do I need to unmount just before switching page? If so, how can I do that?
Page1.vue and Page2.vue
<template>
// The template
</template>
<script>
var socket = io(window.SOCKET_URL, {secure: true});
export default {
mounted(){
socket.on('channel:listen', function (data) {
console.log('Page1.vue');
}
}
}
</script>
Solution
<template>
// The template
</template>
<script>
var socket;
export default {
beforeCreate() {
socket = io(window.SOCKET_URL, {secure: true});
},
mounted(){
socket.on('channel:listen', function (data) {
console.log('Page1.vue');
}
},
beforeDestroy() {
socket.close();
},
}
</script>
Whenever you switch the routes the component related to the previous route is destroyed.
So when you switch from Page1 to Page2 , the Page1 component is destroyed. Then when you revisit the route related to Page1 , its instance created again, thus calling all of it lifecycle methods again including mounted()
where you start listening to you socket.
This is the default behavior of vue. So to tell vue from destroying the components make use of <keep-alive>
.
<keep-alive>
caches the inactive component.
So wrap your router-view with keep-alive as:
<keep-alive>
<router-view>
</router-view>
This caches all the component instances that appear in the router-view.
Here is a codepen.
If you dont want to cache all the routes from the router-view, you can use the include
or exclude
attributes on <keep-alive>
. This tells <keep-alive>
which component instances to cache.
So add name
properties to the route components you want to cache.
//Page1 component script
export default{
name: 'page1',
...
}
<keep-alive include="page1">
<router-view></router-view>
</keep-alive>
The above code only caches Page1 component
alternatively, you can remove the event listener in beforeDestroy
export default {
methods: {
channelListener(data) {
console.log("Page1.vue");
}
},
mounted() {
socket.on("channel:listen", this.channelListener);
},
beforeDestroy() {
socket.off("channel:listen", this.channelListener);
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With