Vue.js performance directives: v-once

Rendering performance is a vital metric for frontend developers. For every second your page takes to render, the bounce rate increases.

And when it comes to creating a smooth user experience? Near instantaneous feedback is key to giving people a responsive app experience.

While Vue is already one of the better performing JavaScript frameworks out of the box, there are ways that developers can improve the performance of their apps.

There are several ways to optimize the rendering of Vue apps - ranging from virtual scrolling to optimizing your v-for elements.

But one extremely easy way to optimize rendering is by only re-rendering what you need to.

Whenever a component’s data changes, that component and its children will re-render, there are ways to eliminate unnecessary tasks with a lesser-used Vue directive: v-once

Let’s jump right in and see how we can use this in our app.

v-once

The v-once directive renders the element/component once and only once. After the initial render, this element and all of its children will be treated as static content.

This can be great for optimizing render performance in your app.

To use this, all we have to do is add v-once to the element in our template. We don’t even need to add an expression like some of Vue’s other directives.

<template>
  <p v-once>{{ msg }}</p>
</template>

It works with single elements, elements with children, components, v-for directives, anything in your template.

//~app.vue

<template>
  <!-- single elements -->
  <p v-once>{{ msg }}</p>
  <!-- elements with children -->
  <div v-once>
    <p>{{ notification}}</p>
  </div>
  <!-- components -->
  <my-component v-once />
  <!-- v-for directives -->
  <li v-for="”item" in list” v-once>{{item}}</li>
</template>

So let’s say we have this example template with some reactive data, a paragraph with v-once, and a button that changes the text.

//~vonceexample.vue

<script setup>
  import { ref } from "vue";
  const msg = ref("hello world");
</script>
<template>
  <div>
    <p v-once>{{ msg }}</p>
    <button @click="msg = 'changed message'">Change message</button>
    <div>
      Current state:
      <p>msg: {{ msg }}</p>
    </div>
  </div>
</template>

When we click our button, we can see that even though the value of msg changes, the paragraph does not change thanks to v-once.

When used with v-if or v-show, once our element is rendered once, the v-if or v-show will no longer apply meaning that if it’s visible on the first render, it will always be visible. And if it’s hidden, it will always be hidden.

<script setup>
import { ref } from 'vue'
const msg = ref('hello world')
const show = ref(false)
</script>
<template>
  <div>
    <p v-once v-if="show">{{ msg }}</p>
    <button @click="show = !show">Toggle</button>
    <button @click="msg = 'changed message'">Change message</button>
    <div>
      Current state:
      <p>msg: {{ msg }}</p>
    </div>
  </div>
</template>

When would I use v-once?

You should use v-once if there is no circumstance that you will need to re-render an element. A couple examples could be:

  • Displaying account information in the sidebar
  • Showing article text
  • Persisting the column names in a table

Obviously, there are tons of other examples - but just think about if this works well in your app.