title: How to prevent parent component from reloading when changing a parameterised child component in Vue js
body: <p>I have a page where a ClientPortfolio (parent component) containing a list of Securities (child component) are loaded in a v-data-table list.</p>
  
  <p><a href="https://i.stack.imgur.com/MfUe9.png" rel="noreferrer"><img src="https://i.stack.imgur.com/MfUe9.png" alt="enter image description here"></a></p>
  
  <p>The issue I have is that ClientPortfolio is fully reloaded every time I click on a security in the list causing the entire list to be refreshed causing scroll and selected class to reset, as well as unncessary performance overhead.
  I have looked at the documentation of Vue and nothing seems to point out how to only refresh a child component when it has parameters, it looks like the parent component is being refreshed as the route is changing every time a security is selected, despite expecting that Vue would <em>know</em> that only sub (nested route) is changing hence need to only reload the child component</p>
  
  <p><a href="https://i.stack.imgur.com/PvIfo.png" rel="noreferrer"><img src="https://i.stack.imgur.com/PvIfo.png" alt="enter image description here"></a></p>
  
  <p>The closest answer I got was explained on <a href="https://github.com/vuejs/vue-router/issues/230" rel="noreferrer">https://github.com/vuejs/vue-router/issues/230</a> which does not explain in the code how to achieve this.</p>
  
  <blockquote>
    <p>routes.js:</p>
  </blockquote>
  
  <pre><code>routes: [
      {
        path: '/client/:clientno/portfolios/:portfolioNo',
        component: ClientPortfolios,
        children: [
          { path: 'security/:securityNo', component: Security }
        ]     
      }, 
    ]
  </code></pre>
  
  <blockquote>
    <p>Router link in ClientPortfolios.vue:</p>
  </blockquote>
  
  <pre><code> &lt;router-link tag="tr" style="cursor:pointer"
                :to="`/client/${$route.params.clientno}/portfolios/${selectedPortfolioSequenceNo}/security/${props.item.SecurityNo}-${props.item.SequenceNo}`"
                :key="props.item.SecurityNo+props.item.SequenceNo"&gt;
  
              &lt;/router-link&gt;
  </code></pre>
  
  <blockquote>
    <p>Router view (for Security component) in ClientPortfolios.vue:</p>
  </blockquote>
  
  <pre><code>&lt;v-flex xs10 ml-2&gt;
        &lt;v-layout&gt;
            &lt;router-view :key="$route.fullPath"&gt;&lt;/router-view&gt;
        &lt;/v-layout&gt;
      &lt;/v-flex&gt;
  </code></pre>
  
  <p>Any hint on how to prevent parent from getting reloaded is appreciated.</p>
  
  <p>EDIT: Trying to get closer to the issue, I notice that the "Key" attr in ClientPortfolios changes (as shown in the Vue debug window above) whenever I change the Security, could that be the reason? Is there a way to assign a key to ClientPortfolios component although its not a child one? Or a way to not update its key when navigating to different securities?</p>
  
  <p>UPDATE: Full code</p>
  
  <blockquote>
    <p>ClientPortfolios.vue</p>
  </blockquote>
  
  <pre><code>&lt;template&gt;
    &lt;v-layout row fill-height&gt;
      &lt;v-flex xs2&gt;
        &lt;v-layout column class="ma-0 pa-0 elevation-1"&gt;
          &lt;v-flex&gt;
            &lt;v-select v-model="selectedPortfolioSequenceNo" :items="clientPortfolios" box label="Portfolio"
              item-text="SequenceNo" item-value="SequenceNo" v-on:change="changePortfolio"&gt;
            &lt;/v-select&gt;
          &lt;/v-flex&gt;
          &lt;v-data-table disable-initial-sort :items="securities" item-key="Id" hide-headers hide-actions
            style="overflow-y: auto;display:block;height: calc(100vh - 135px);"&gt;
            &lt;template slot="items" slot-scope="props"&gt;
              &lt;router-link tag="tr" style="cursor:pointer"
                :to="{ name: 'Security', params: { securityNo: props.item.SecurityNo+'-'+props.item.SequenceNo } }"
                &gt;
              &lt;/router-link&gt;
  
            &lt;/template&gt;
            &lt;template v-slot:no-data&gt;
              &lt;v-flex class="text-xs-center"&gt;
                No securities found
              &lt;/v-flex&gt;
            &lt;/template&gt;
          &lt;/v-data-table&gt;
        &lt;/v-layout&gt;
      &lt;/v-flex&gt;
  
      &lt;v-flex xs10 ml-2&gt;
        &lt;v-layout&gt;
          &lt;keep-alive&gt;
            &lt;router-view&gt;&lt;/router-view&gt;
          &lt;/keep-alive&gt;
        &lt;/v-layout&gt;
      &lt;/v-flex&gt;
    &lt;/v-layout&gt;
  
  &lt;/template&gt;
  &lt;script&gt;
    import Security from '@/components/Security'
  
    export default {
      components: {
  
        security: Security
      },
      data () {
        return {
          portfoliosLoading: false,
          selectedPortfolioSequenceNo: this.$route.params.portfolioNo,
          selectedPortfolio: null,
          securityNo: this.$route.params.securityNo
        }
      },
      computed: {
        clientPortfolios () {
          return this.$store.state.ClientPortfolios
        },
        securities () {
          if (this.clientPortfolios == null || this.clientPortfolios.length &lt; 1) {
            return []
          }
          let self = this
          this.selectedPortfolio = global.jQuery.grep(this.clientPortfolios, function (portfolio, i) {
            return portfolio.SequenceNo === self.selectedPortfolioSequenceNo
          })[0]
  
          return this.selectedPortfolio.Securities
        }
      },
      mounted () {
        this.getClientPortfolios()
      },
      activated () {
      },
      methods: {
        changePortfolio () {
          this.$router.push({
            path: '/client/' + this.$route.params.clientno + '/portfolios/' + this.selectedPortfolioSequenceNo
          })
        },
        getClientPortfolios: function () {
          this.portfoliosLoading = true
          let self = this
          this.$store.dispatch('getClientPortfolios', {
            clientNo: this.$route.params.clientno
          }).then(function (serverResponse) {
            self.portfoliosLoading = false
          })
        }
      }
    }
  &lt;/script&gt;
  </code></pre>
  
  <blockquote>
    <p>Security.vue</p>
  </blockquote>
  
  <pre><code>&lt;template&gt;
    &lt;v-flex&gt;
      &lt;v-layout class="screen-header"&gt;
        &lt;v-flex class="screen-title"&gt;Security Details &lt;/v-flex&gt;
  
      &lt;/v-layout&gt;
      &lt;v-divider&gt;&lt;/v-divider&gt;
      &lt;v-layout align-center justify-space-between row class="contents-placeholder" mb-3 pa-2&gt;
        &lt;v-layout column&gt;
          &lt;v-flex class="form-group" id="security-portfolio-selector"&gt;
            &lt;label class="screen-label"&gt;Sequence&lt;/label&gt;
            &lt;span class="screen-value"&gt;{{security.SequenceNo}}&lt;/span&gt;
          &lt;/v-flex&gt;
          &lt;v-flex class="form-group"&gt;
            &lt;label class="screen-label"&gt;Security&lt;/label&gt;
            &lt;span class="screen-value"&gt;{{security.SecurityNo}}-{{security.SequenceNo}}&lt;/span&gt;
          &lt;/v-flex&gt;
  
          &lt;v-flex class="form-group"&gt;
            &lt;label class="screen-label"&gt;Status&lt;/label&gt;
            &lt;span class="screen-value-code" v-if="security.Status !== ''"&gt;{{security.Status}}&lt;/span&gt;
          &lt;/v-flex&gt;
        &lt;/v-layout&gt;
  
      &lt;/v-layout&gt;
  
    &lt;/v-flex&gt;
  
  &lt;/template&gt;
  &lt;script&gt;
    export default {
      props: ['securityNo'],
      data () {
        return {
          clientNo: this.$route.params.clientno,
          securityDetailsLoading: false
        }
      },
      computed: {
        security () {
          return this.$store.state.SecurityDetails
        }
      },
  
      created () {
        if (this.securityNo.length &gt; 1) {
          this.getSecurityDetails()
        }
      },
  
      methods: {
        getSecurityDetails: function () {
          let self = this
          this.securityDetailsLoading = true
  
          this.$store.dispatch('getSecurityDetails', {
            securityNo: this.securityNo,
            clientNo: this.clientNo
  
          }).then(function (serverResponse) {
            self.securityDetailsLoading = false
          })
        }
      }
    }
  &lt;/script&gt;
  </code></pre>
  
  <blockquote>
    <p>router.js</p>
  </blockquote>
  
  <pre><code>const router = new Router({
    mode: 'history',
    routes: [
      {
        path: '/',
        component: Dashboard
      },
      {
        path: '/client/:clientno/details',
        component: Client,
        props: true
      },
  
      {
        path: '/client/:clientno/portfolios/:portfolioNo',
        component: ClientPortfolios,
        name: 'ClientPortfolios',
        children: [
          { path: 'security/:securityNo',
            component: Security,
            name: 'Security'
          }
        ]
      }
    ]
  })
  </code></pre>
  
  <p><strong>UPDATE</strong>:</p>
  
  <p>Just to update this as it’s been a while, I finally got to find out what the problem is, which is what @matpie indicated elsewhere, I have found out that my App.vue is the culprit where there is a :key add to the very root of the application: <code>&lt;router-view :key="$route.fullPath" /&gt;</code> this was a template I used from somewhere but never had to look at as it was "working", after removing the key, all is working as it should, marking matpie answer accepted.</p>