Menu Close

How to Conditionally Render Elements in Vue

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at various ways to render items conditionally on the screen with Vue.js by using the v-show directive.

Also, we’ll look at the performance implications of combining v-if and v-for is various ways.

v-show

The v-show directive is used to show something when the expression we passed into it is truthy.

For example, we can use it as follows:

<h1 v-show="show">Hi</h1>

The difference between v-show and v-if are that v-show elements remain in the DOM even though is hidden.

On the other hand, v-if elements are hidden by removing them from the DOM.

Also, v-if removes event listeners and child components inside conditional blocks are destroyed if they’re hidden and recreated when v-if ‘s expression is truthy.

v-if elements are also different in that if the condition is falsy during conditional render, it won’t do anything. It won’t be rendered until the expression becomes truthy.

v-if has higher toggling than v-show since DOM manipulating and attaching event listeners have to be done when things are toggled.

Therefore, if things need to be toggled often, v-show is more efficient.

v-if with v-for

v-for has higher priority than v-if if they’re used together.

However, we shouldn’t use them together because of the higher precedence of v-for over v-if .

If we want to filter some elements out when we render items from an array, we should use a computed property.

If we only render a small fraction of array elements, it has to iterate over the entire list and then check if the expression we set it truthy.

For example, the following JavaScript and HTML code:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    persons: ["Joe", "Jane", "Mary"]  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  <body>  
    <div id="app">  
      <div v-for="person in persons" v-if='person !== "Joe"'>  
        {{person}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

is not very efficient since every time the loop is rendered, Vue has to iterate through every element and then check if person !== “Joe” is true .

Instead, we should use a computed property as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    persons: ["Joe", "Jane", "Mary"]  
  },  
  computed: {  
    personsWithoutJoe() {  
      return this.persons.filter(p => p !== "Joe");  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  <body>  
    <div id="app">  
      <div v-for="person in personsWithoutJoe">  
        {{person}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The code above is more efficient because personsWithoutJoe is only recomputed when persons change.

Also, only the items in personsWithoutJoe is iterated through during render, so v-for doesn’t have to loop through all the items.

There’s also less logic in the template, which keeps it clean. Maintenance is much easier.

We can also get performance benefits from moving v-if to the parent element that has the v-for , so whatever’s inside is only rendered when the condition is met.

For example, if we have:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    persons: ["Joe", "Jane", "Mary"],  
    show: false  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  <body>  
    <div id="app">  
      <div v-if="show">  
        <div v-for="person in persons">  
          {{person}}  
        </div>  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then nothing is rendered since show is false . Vue doesn’t have to do the work to look at whatever’s inside.

This is much better than:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  <body>  
    <div id="app">  
      <div v-for="person in persons" v-if="show">  
        {{person}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, Vue has to loop through each entry and check if the condition in the v-if returns a truthy value.

As we can see, even though the code is only slightly different, but the performance implications are big.

Conclusion

v-show is similar to v-if , except that items with v-show stays in the DOM no matter if it’s shown or not.

Also, we should be careful when we combine v-for and v-if .

First, v-for takes precedence over v-if if applied to the same element.

Also, we shouldn’t use them on the same element since Vue has to check each element for v-if ‘s condition in every iteration.

If we want to render a filtered list, we should use a computed property.

If we want to check if we should render the whole array, we should move v-if to the parent of the element with v-for , so that if v-if ‘s condition is falsy, then Vue won’t render the items in there.

Posted in vue