Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait until parent component is mounted / ready before rendering child in vue.js

In my SPA app, I have an <app-view> wrapper which handles base app code (load user data, render navbar and footer, etc) and has a slot for rendering the actual page. This slot is rendered only if the user data is available.

This wrapper was created because some pages needed a different base code, therefore I couldn't keep this base code in the main app containing <router-view> anymore.

I tried looking if vue-router provides advanced options or suggests a design pattern for switching base code, didn't find anything.

The problem is that the child component will be rendered before the parent component is mounted, i.e. before the parent decides not to render the child component (because it's loading user data). This causes errors like undefined as no attribute foo.

Because of that, I'm looking for a way to defer child rendering until its parent is mounted.

like image 893
megapctr Avatar asked Feb 13 '18 12:02

megapctr


3 Answers

I had a similar problem though not with a SPA. I had child components that needed data from the parent. The problem is that the data would only be generated after the parent has finished mounting so I ended up with null values in the children.

This is how I solved it. I used v-if directive to mount the children only after the parent has finished mounting. (in the mounted() method) see the example below

<template>
  <child-component v-if="isMounted"></child-component>
</template>
<script>
  data() {
     isMounted: false
  }, mounted() {
     this.isMounted = true
  }
</script>

After that, the child could get the data from the parent. It is slightly unrelated but I hope it gives you an idea.

like image 70
Stanley Avatar answered Sep 21 '22 06:09

Stanley


After trying a few options, it looks like I need to bite the bullet and explicitly define the data that my components depend on, like so:

<app-view>
  <div v-if='currentProfile'>
    ...
  </div>
</div>

(currentProfile is received from vuex store getter, and is fetched within app-view)

like image 31
megapctr Avatar answered Sep 22 '22 06:09

megapctr


For any of you that wants to show the child component as soon as the parent components gets data from an API call then you should use something like this:

<template>
  <child-component v-if="itemsLoaded"></child-component>
</template>

<script>
  data() {
     itemsLoaded: false
  },
  methods: {
      getData() {
          this.$axios
              .get('/path/to/endpoint')
              .then((data) => {
                  // do whatever you need to do with received data
                  
                  // change the bool value here
                  this.itemsLoaded = true
          })
          .catch((err) => {
              console.log(err)
          })
      },
  }, 
  mounted() {
     this.getData()

     // DONT change the bool value here; papa no kiss
     this.itemsLoaded = true
  }
</script>

If you try to change the boolean value this.itemsLoaded = true in the mounted() method, after calling the getData() method, you will get inconsistent results, since you may or may not receive the data before the this.itemsLoaded = true is executed.

like image 40
christostsang Avatar answered Sep 22 '22 06:09

christostsang