Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue router mounted twice when switching page

Tags:

vue.js

I'm using vue-router for switching pages. Now I have two Vue documents:

  • Page1.vue
  • Page2.vue

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>
like image 757
Timo002 Avatar asked Jan 28 '23 04:01

Timo002


2 Answers

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

like image 180
Vamsi Krishna Avatar answered Feb 07 '23 12:02

Vamsi Krishna


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);
  }
};
like image 31
Jacob Goh Avatar answered Feb 07 '23 12:02

Jacob Goh