DEV Community

noah Ren
noah Ren

Posted on

7 ways to write Vue v-for loops more elegantly

In Vue, basically every project will use v-for loop. They allow you to write for loops in template code.

This is especially useful in situations such as:

render array or list
Iterate over object properties
The most basic usage of v-for loop in Vue is like this:

<ul>
  <li v-for='product in products'>
    {{ product.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

However, in this article, we'll cover some awesome ways to make your v-for code more precise, predictable, and efficient.

let's start.

1. Always use key in v-for loop
First, we're talking about a common best practice that most Vue developers already know - using :key in v-for loops. By setting a unique key property, you can ensure that the component works as expected.

If we don't use :key, Vue will make the DOM as efficient as possible. This can lead to out-of-order or other unpredictable behavior of v-for elements.

If we have a unique key reference to each element, then we can better predict how to manipulate the DOM.

<ul>
  <li 
    v-for='product in products'
    :key='product._id'  
  >
    {{ product.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

2. Use v-for loop in a certain range
While most of the time v-for is used to loop over arrays or objects, there are also cases where we only want to iterate a specific number of times.

For example, let's say we are creating a pagination system for an online store and we only want to display 10 products per page. Using a variable to keep track of the current page number, you can handle pagination like this.

<ul>
  <li v-for='index in 10' :key='index'>
    {{ products[page * 10 + index] }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

3. Avoid using v-if in loops
A super common mistake is to use v-if to filter data in a v-for loop.

While it seems intuitive, this leads to a huge performance issue - VueJS will prefer v-for over v-if directives.

This means that the component will iterate over each element before checking the v-if condition to see if it should render.

If you use v-if with v-for, it will iterate over every item of the array no matter what the condition is:

<ul>
  <li 
    v-for='product in products' 
    :key='product._id' 
    v-if='product.onSale'
  >
    {{ product.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

4. Using computed properties or methods
To avoid the above problem, we should filter the data before iterating in the template. There are two very similar ways to do it:

Using the computed property
Use filter method
The choice is yours, let's take a quick look at both methods below.

First, we just need to set a computed property. To get the same functionality as the previous v-if, the code looks like this.

<template>
  <ul>
    <li v-for="products in productsOnSale" :key="product._id">
      {{ product.name }}
    </li>
  </ul>
</template>

<script>
  export default {
    data () {
      return {
        products: []
      }
    },
    computed: {
      productsOnSale: function () {
        return this.products.filter(product => product.onSale)
      }
    }
  }
</script>
Enter fullscreen mode Exit fullscreen mode

The benefits of this are:

  1. Data properties will only be re-evaluated when dependencies change;
  2. The template only loops through the products on sale, not every product; The code for using the filter method is almost the same, but using the method changes how the values inside the template are accessed. However, if we want to be able to pass variables to the filtering process, then the method should be the way to go.
<template>
  <ul>
    <li v-for="products in productsOnSale(50))" :key="product._id">
      {{ product.name }}
    </li>
  </ul>
</template>

<script>
  export default {
   data () {
    return {
     products: []
    }
   },
   methods: {
    productsOnSale (maxPrice) {
     return this.products.filter(product => product.onSale && product.price < maxPrice)
    }
   }
  }
</script>
Enter fullscreen mode Exit fullscreen mode

5. Or wrap a layer of elements in the loop
You may still want to combine v-for with v-if when deciding whether to render the list at all.

For example, what if we only want to render a list of products when the user is logged in.

error code:

<ul>
  <li 
    v-for='product in products' 
    :key='product._id' 
    v-if='isLoggedIn' <!-- HERE -->
  >
    {{ product.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

What's wrong with this?

Same as before. Vue templates will prioritize v-for - so will iterate over each element and check for v-if.

Even if nothing is rendered at the end, it loops through thousands of elements.

For this example, there is an easy solution to move the v-if statement.

better code!

<ul v-if='isLoggedIn'> <!-- Much better -->
  <li 
    v-for='product in products' 
    :key='product._id' 
  >
    {{ product.name }}
  </li>
</ul
Enter fullscreen mode Exit fullscreen mode

This is much better because if isLoggedIn is false - then there is no need to iterate at all.

6. Access the index in the loop
In addition to traversing the array and accessing each element, we can also keep track of the index of each item.

To do this, we need to add an index value after the item. This is super easy to do, but useful for pagination, showing list indexes, showing rankings, etc.

<ul>
  <li v-for='(products, index) in products' :key='product._id' >
    Product #{{ index }}: {{ product.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

7. Iterating over objects
So far, we've only looked at using v-for to iterate over arrays. But we can also easily learn to iterate over key-value pairs of objects.

Similar to accessing the index of an element, we need to add another value to the loop. If we loop over objects with a single argument, we loop over all items.

If we add another parameter, we will get the item and key. If we add a third parameter, we can also access the index of the v-for loop.

Suppose we want to iterate over every attribute in a product. Then the code is as follows:

<ul>
  <li v-for='(products, index) in products' :key='product._id' >
    <span v-for='(item, key, index) in product' :key='key'>
      {{ item }}
    </span>
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

In conclusion
Hopefully this article helped you learn some best practices for using the Vue v-for directive.

Thanks for reading, and happy coding everyone!

Top comments (0)