Performance Optimization Techniques for Vue.js Applications

Performance Optimization Techniques for Vue.js Applications

Make your websites/apps fast with strategies like lazy loading, stable prop design, virtual lists, v-once and v-memo, plus more!

Daniel Kelly

Daniel Kelly

September 16, 2024

Vue.js is known for its excellent performance out of the box, but as applications grow in complexity, it's crucial to implement optimization techniques to ensure they remain fast and responsive. This article will explore various strategies to enhance the performance of your Vue.js applications.

TLDR: Checkout out course all about optimizing your Vue.js apps for blazing fast performance TODO: insert link here

1. Implement Lazy Loading

Lazy loading is a technique that delays the loading of non-critical resources at page load time. In Vue.js, this can be achieved using dynamic imports.

  • Do: Lazy load routes and components that aren't immediately necessary.
  • Don't: Lazy load small, frequently used components as this can negatively impact performance.

Example:

const UserDashboard = () => import('./components/UserDashboard.vue')

const router = createRouter({
  routes: [
    { path: '/dashboard', component: UserDashboard }
  ]
})

If you’re working in a Nuxt application this is automatically done for routes, and components can be lazy loaded by prefixing them with the Lazy keyword.

<LazyMyComponent v-if="showMyComponent" />

2. Optimize Rendering with v-show and v-if

Vue.js provides two directives for conditionally rendering elements: v-show and v-if. Understanding when to use each can improve your app's performance.

  • Use v-show: When the condition changes frequently and the element is large or complex.
  • Use v-if: When the condition rarely changes or when you need to conditionally render multiple elements.

Example:

<!-- Frequently toggled -->
<div v-show="isVisible">Heavy content</div>

<!-- Rarely changed -->
<div v-if="isLoggedIn">
  <user-profile></user-profile>
  <user-settings></user-settings>
</div>

3. Use Key Attribute with v-for

When using v-for to render lists, always use the key attribute with a unique value. This helps Vue optimize re-renders and improves overall performance.

  • Do: Use unique, stable IDs as keys.
  • Don't: Use index as a key

Example:

<ul>
  <li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>

4. Implement Pagination or Virtual Scrolling for Large Lists

When dealing with large datasets, rendering all items at once can significantly slow down your application.

  • Do: Implement pagination or virtual scrolling for long lists.
  • Don't: Render thousands of items in a single view.

Example using a third-party library like vue-virtual-scroller:

<template>
  <RecycleScroller
    class="scroller"
    :items="items"
    :item-size="32"
  >
    <template v-slot="{ item }">
      <div class="user">
        {{ item.name }}
      </div>
    </template>
  </RecycleScroller>
</template>

5. Use Plain Values for Data that Doesn’t Change

Not all data has to be defined as reactive data with the ref function. If it’s some hardcoded configuration object you can save a bit of memory as Vue doesn’t have to watch the data for changes.

  • Do: Define unchanging data without the ref or reactive function.
  • Don't: Forget to use ref or reactivif you do need reactivity.

Example:

<script setup>
const navItems = [
  { label: "Home", link: "/" },
  { label: "About", link: "/about" },
  { label: "Blog", link: "/blog" },
  { label: "Contact Me", link: "/contact" },  
]
</script>
<template>

<nav>
    <ul>
        <li v-for="item in navItems" :key="item.link" >
        ...
        </li>
    </ul>
</nav>
</template>

6. Use Shallow Refs for Large Datasets

By default, Vue is deeply reactive. This is great for DX but can cause performance issues with large datasets. Replace ref with shallowRef when working with arrays with 1000s of items and trigger updates by replacing the entire array.

  • Do: Define large datasets with shallowRef.
  • Don't: Forget to replace the entire dataset if you want to trigger an update.

Example:

const mySuperBigArray = shallowRef([
  // thousands of items in here
]);

function addNewItemToMySuperBigArray(newItem){
  // ❌ this won't trigger updates to the DOM
  mySuperBigArray.value.push(newItem)
  
  // ✅ instead replace the entire dataset
  mySuperBigArray.value = [...mySuperBigArray.value, newItem]
}

7. Use v-once and v-memo to Skip Sub-Tree Updates

Vue.js provides two powerful directives, v-once and v-memo, that can help optimize rendering performance by skipping unnecessary updates to parts of your template.

v-once

The v-once directive renders an element or component once and then skips future updates. This is useful for content that never needs to change.

  • Do: Use v-once for static content that won't change after initial render.
  • Don't: Use v-once on elements that might need to update based on changing data.

Example:

<template>
  <div>
<!-- This will only be rendered once -->
    <h1 v-once>{{ title }}</h1>

<!-- This will update as usual -->
    <p>{{ dynamicContent }}</p>
  </div>
</template>

v-memo

The v-memo directive allows you to memoize a sub-tree of your template. It takes an array of dependencies and only re-renders the sub-tree when one of these dependencies changes.

  • Do: Use v-memo for expensive sub-trees that depend on specific values.
  • Don't: Overuse v-memo, as it adds complexity and can harm performance if used incorrectly.

Example:

<template>
  <div>
    <div v-memo="[item.id, item.completed]">
<!-- This block will only re-render when item.id or item.completed changes -->
      <span>{{ item.name }}</span>
      <span>{{ item.description }}</span>
      <complex-component :data="item.data"></complex-component>
    </div>
  </div>
</template>

In this example, the content inside the v-memo directive will only re-render if item.id or item.completed changes, even if other properties of item are updated.

8. Design Components with Stable Props

In Vue, a child component only updates when at least one of its received props has changed. Therefore you should design props to change only when necessary.

  • Do: Think about prop stability when designing performant components
  • Don't: Over think it. The solution is usually pretty straight forward.

Example:

 <!--this will re-render every ListItem component 
 in the list when activeId changes-->
<ListItem
  v-for="item in list"
  :id="item.id"
  :active-id="activeId" />
 
<!--this will only re-render the ListItem that's becoming active 
 and the one that is becoming inactive-->
<ListItem
  v-for="item in list"
  :id="item.id"
  :active="item.id === activeId" />

Conclusion

Optimizing Vue.js applications involves a combination of using Vue's built-in features effectively and implementing general web performance best practices. By applying these techniques, you can ensure your Vue.js applications remain fast and responsive, providing an excellent user experience even as they grow in complexity.

Remember, performance optimization is an ongoing process. Always measure the impact of your optimizations using Vue's devtools and browser performance profiling tools to ensure you're making meaningful improvements.

If you'd like to test your skills and deepen your knowledge of making your Vue.js apps performant, checkout the Senior Vue.js Developer Exam.

More certificates.dev articles

Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

Looking for Certified Developers?

We can help you recruit Certified Developers for your organization or project. The team has helped many customers employ suitable resources from a pool of 100s of qualified Developers.

Let us help you get the resources you need.

Contact Us
Customer Testimonial for Hiring
like a breath of fresh air
Everett Owyoung
Everett Owyoung
Head of Talent for ThousandEyes
(a Cisco company)