Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VueJS component wont render until I click on it in Vue Devtools

I am using VueJS 2.5.3 on a section (not SPA) of a blog backend that makes an API call to check for a featured image attached to the post.

If it finds one, it uses a child component to show the image. The problem is that the child component isn't rendering after the API call is successful and so neither is the image object passed to it.

As you can see in this GIF, the child component isn't rendering <!---->, I have a v-if on it to check if the image exists. However, if I click on the child component inside of Vue DevTools, the child component renders and shows the image as expected.

My question is why would a child component only render after clicking on it in Vue Devtools? Does Vue Devtools trigger some sort of an event when you click on a component?

Here is the child component:

<template>
    <div v-if="showImage" class="featured-image-container" :class="[ size ]">
        <img :src="processedSrc" alt="Featured Image">
    </div>
</template>

<script>
export default {
    props: {
        image: {
            type: Object
        },
        size: {
            type: String,
            required: true
        }
    },
    data () {
        return {
            showImage: false
        }
    },
    computed: {
        processedSrc: function () {
            if (this.image && typeof this.image === 'object') {
                this.showImage = true
                return this.image.sizes[this.size].file
            } else {
                this.showImage = false
            }
        }
    }
}
</script>

And here is a link to the code for the parent and child components:

like image 705
ATLChris Avatar asked Nov 06 '17 21:11

ATLChris


1 Answers

The issue is in your PostFeaturedImage.vue component. You are depending on a computed value processedSrc to set a data property showImage.

However, showImage is initially false and you are using it in the v-if directive on the root element. This means that Vue will not render that element or the <img> element inside of it.

Computed properties in Vue are lazy-loaded, meaning their functions are not called until they are referenced. Since the processedSrc computed property is only being referenced on the <img> element (and since that element is not being rendered) its method is not getting called, meaning the showImage property is never set to true.

However, when you inspect a component in Vue DevTools, it lists all of the computed properties, meaning that the method for the processedSrc computed is getting called, and the showImage property is being set in that case.


The easiest solution to your issue would be to use v-show instead of v-if, since elements inside a v-show will be hidden but still rendered even if the value is false.

However, I would almost never recommend setting a data property's value based on logic within a function for a computed property. It creates unintended, hard-to-debug side-effects which lead to issues like the one you're currently experiencing.

I would suggest making your showImage property a computed property as well, based on the logic currently determining its value in the processedSrc computed method. Then, you can determine whether or not to try to calculate the value of the processedSrc computed based on the value of showImage.

computed: {
  showImage: function() {
    return this.image && typeof this.image === 'object';
  },
  processedSrc: function () {
    if (this.showImage) {
      return this.image.sizes[this.size].file;
    }
  }
}

This way, it is much easier to see what is affecting what and your code will be easier to maintain.

like image 134
thanksd Avatar answered Nov 09 '22 08:11

thanksd