Paul
Paul

Reputation: 1264

Vue re-creates the parent component when changes routes

I'm using Vue.js with Vue-router in a project and the problem is that the component that includes router-view is destroyed when the route is changed. This means all the other components on the page are destroyed so the whole thing looks like a page refresh.

I recently started working with Vue and the application I'm working on is filled with lots of legacy code and very difficult to reduce to the basics, so it's hard for me to isolate the problem.

I tried to reproduce the problem in a fiddle, but with no success. Here's the templates code:

<div id="router-app">
  <router-view></router-view>
</div>

<template id="tricky-place">
  <div>
    <h1>Tricky place</h1>
    <ul>
      <li>
        <router-link to="/panel1">Panel1</router-link>
      </li>
      <li>
        <router-link to="/panel2">Panel2</router-link>
      </li>
    </ul>
    <router-view></router-view>
  </div>
</template>

<template id="tricky-place-panel1">
  <div>
    <h2>Panel1</h2>
  </div>
</template>

<template id="tricky-place-panel2">
  <div>
    <h2>Panel2</h2>
  </div>
</template>

and the script:

const TrickyPlace = Vue.component('tricky-place', {
    created() {
      console.log("TrickyPlace - created");
    },
    mounted() {
        console.log("TrickyPlace - mounted");
    },
    updated() {
        console.log("TrickyPlace - updated");
    },
    destroyed() {
       console.log("TrickyPlace - destroyed");
    },
  template: '#tricky-place'
});

const TrickyPlacePanel1 = Vue.component('tricky-place-panel1', {
  created() {
    console.log("TrickyPlacePanel1 - created");
  },
  mounted() {
    console.log("TrickyPlacePanel1 - mounted");
  },
  updated() {
    console.log("TrickyPlacePanel1 - updated");
  },
  destroyed() {
    console.log("TrickyPlacePanel1 - destroyed");
  },
  template: '#tricky-place-panel1'
});

const TrickyPlacePanel2 = Vue.component('tricky-place-panel2', {
  created() {
    console.log("TrickyPlacePanel2 - created");
  },
  mounted() {
    console.log("TrickyPlacePanel2 - mounted");
  },
  updated() {
    console.log("TrickyPlacePanel2 - updated");
  },
  destroyed() {
    console.log("TrickyPlacePanel2 - destroyed");
  },
  template: '#tricky-place-panel2'
});

const routes = [{
  path: '/',
  component: TrickyPlace,
  children: [{
    path: 'panel1',
    component: TrickyPlacePanel1
  }, {
    path: 'panel2',
    component: TrickyPlacePanel2
  }, ]
}]
const router = new VueRouter({
  routes
});

const routerApp = new Vue({
  router,
  el: '#router-app',
});

Here's the fiddle: https://jsfiddle.net/loorker/m1hncLb0/15/

Here's the console log when I load the fiddle, click on Panel1, then on Panel2:

TrickyPlace - created
TrickyPlace - mounted

TrickyPlacePanel1 - created
TrickyPlacePanel1 - mounted
TrickyPlace - updated

TrickyPlacePanel2 - created
TrickyPlacePanel1 - destroyed
TrickyPlacePanel2 - mounted
TrickyPlace - updated

This is as expected.

And here's the console log for the same sequence of operations when I run the same code inside my application:

TrickyPlace - created
TrickyPlace - mounted

TrickyPlace - created
TrickyPlacePanel1 - created
TrickyPlace - destroyed
TrickyPlacePanel1 - mounted
TrickyPlace - mounted

TrickyPlace - created
TrickyPlacePanel2 - created
TrickyPlacePanel1 - destroyed
TrickyPlace - destroyed
TrickyPlacePanel2 - mounted
TrickyPlace - mounted

TrickyPlace is destroyed and created upon each route change, instead of being updated as in the fiddle.

In other words, considering the figure in https://v2.vuejs.org/v2/guide/instance.html what happens in my application is that in the red circle that states Mounted, the execution flow doesn't take the "when data changes" path, but goes directly to "when vm.$destroy() is called".

I tried setting the router's mode to "history" but it behaves the same. There is no call for $destroy() nowhere in the application. I have no :key binding set on the router-view.

Any thoughts on how I may proceed to find the issue, why the created/destroy is called for the parent, instead of just update?

Thanks.

Upvotes: 4

Views: 2258

Answers (1)

Paul
Paul

Reputation: 1264

Just found the issue. There was a <router-view> with :key="$route.fullPath" higher up in the components hierarchy ...

As described here:

If you bind key to $route.fullPath, it will always "force a replacement" of the <router-view> element / component every time a navigation event occurs.

Upvotes: 9

Related Questions