Post cover

How to Use nextTick() in Vue

Updated March 26, 2023

A change to Vue component's data (props or state) isn't immediately reflected in the DOM. Rather, Vue updates DOM asynchronously.

You can catch the moment when Vue updates DOM using Vue.nextTick() or vm.$nextTick() functions. Let's see in detail how these functions work.

Before I go on, let me recommend something to you.

Using Vue composition API is fun... but sometimes challenging. Take "Vue 3 Composition API" course by Vueschool to become proficient in Vue composition and reactivity in just a few weekends!

1. nextTick()

As Vue component data changes, the DOM is updated asynchronously. Vue collects multiple updates to virtual DOM from all the components, and then creates a single batch to update the DOM.

Updating DOM in a single batch is more performant than doing multiple small updates.

For example, let's consider a component that toggles the display of an element:


<script setup>
import { ref } from 'vue'
const show = ref(true)
const content = ref()
const handleClick = () => {
show.value = !show.value
console.log(show.value, content.value)
}
</script>
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>

Open the demo.

Clicking on "Insert/Remove" button changes show flag, which toggles the display of <div id="content"> element using v-if="show" directive.

Looking into handleClick, right after data mutation show.value = !show.value, the logged DOM data doesn't correspond to show value. If show is true, then content is null: which means that DOM is not in sync with the component's data.

If you want to catch the moment when DOM has just been updated, then you need to use a special function nextTick(callback). It executes callback after the new data updates have reached DOM.

Let's find the moment when the <div> element is inserted or removed from the DOM:


<script setup>
import { ref, nextTick } from 'vue'
const show = ref(true)
const content = ref()
const handleClick = () => {
show.value = !show.value
nextTick(() => {
console.log(show.value, content.value)
})
}
</script>
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>

Open the demo.

Open the demo and click a few times the Insert/Remove button. You'd see that content (the reference that contains the <div> element) is null or contains an element in exact correspondence with show value.

Also, nextTick(callback) executes the callback when all children components updates have been submitted to DOM.

There's also this.$nextTick(callback) available on the component instance, which you might find useful in the case of options API.

2. nextTick() with async/await

If nextTick() is called without arguments, it will return a promise that resolves when component data changes reach DOM.

This helps to take advantage of the more readable async/await syntax.

For example, let's make the previous component more readable by catching the DOM update with the async/await syntax:


<script setup>
import { ref, nextTick } from 'vue'
const show = ref(true)
const content = ref()
const handleClick = async () => {
show.value = !show.value
await nextTick()
console.log(show.value, content.value)
}
</script>
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>

Open the demo.

const handleClick = async () => {...} has been marked as an asynchronous function.

When the Insert/Remove button is clicked, the value of show changes.

await nextTick() awaits until the changes reach DOM. Finally, console.log(content) logs the actual content of the reference.

My recommendation is to use the nextTick() with the async/await syntax, as it's more readable than the callback approach.

3. Conclusion

When you change the component's data, Vue updates the DOM asynchronously.

If you want to catch the moment when DOM has been updated after the component's data change, then you need to use nextTick(callback) or this.$nextTick(callback) (options API) functions.

Their single callback argument is invoked right after DOM update: and you are guaranteed to get the latest DOM in sync with the component's data.

Alternatively, if you don't pass the callback argument to nextTick(): the functions will return a promise that'll be resolved when DOM is updated.

I recommend using nextTick() with async/await syntax for better readability.

Like the post? Please share!

Dmitri Pavlutin

About Dmitri Pavlutin

Software developer and sometimes writer. My daily routine consists of (but not limited to) drinking coffee, coding, writing, overcoming boredom 😉. Living in the sunny Barcelona. 🇪🇸