I read the docs, but I can\'t understand it. I know what data, computed, watch, methods do but what is nextTick()
use for in vuejs?
The content has been taken from By Adrià Fontcuberta
Vue documentation says:
Vue.nextTick( [callback, context] )
Defer the callback to be executed after the next DOM update cycle. Use it immediately after you’ve changed some data to wait for the DOM update.
Hmm..., if it feels intimidating at first, do not worry I will try to explain it as simple as possible. But first there are 2 things you should know:
Its usage is uncommon. Like one of those silver magic cards. I have written several Vue
apps and ran into nextTick() once or twice.
It’s easier to understand once you’ve seen some real use cases. After you get the idea, the fear will go away, and you will have a handy tool under your belt.
Let’s go for it, then.
We are programmers, aren’t we? We’ll use our beloved divide and conquer approach to try to translate the description of .nextTick()
bit by bit. It starts with:
Defer the callback
Ok, now we know it accepts a callback. So it looks like this:
Vue.nextTick(function () {
// do something cool
});
Great. This callback is deferred (this is how millenials say delayed) until…
the next DOM update cycle.
Okay. We know that Vue performs DOM updates asynchronously. It features a way of keeping these updates “stored” until it needs to apply them. It creates a queue of updates and flushes it when needed. Then, the DOM is “patched” and updated to its latest version.
What?
Let me try again: Imagine your component does something really essential and smart like this.potatoAmount = 3.
Vue won’t re-render the component (and thus the DOM) automatically. It’ll queue up the required modification. Then, in the next “tick” (as in a clock), the queue is flushed, and the update is applied. Tada!
Okay! So we know that we can use nextTick()
to pass a callback function that is executed right after the data is set and the DOM has updated.
As I said earlier… not that often. The “data flow” approach that drives Vue, React, and the other one from Google, which I won't mention, makes it unnecessary most of the time. Yet, sometimes we need to wait for some elements to appear/disappear/be modified in the DOM. This is when nextTick comes in handy.
Use it immediately after you’ve changed some data to wait for the DOM update.
Exactly! This is the last piece of definition that Vue docs provided to us. Inside our callback, the DOM has been updated so we can interact with the “most updated” version of it.
Prove it
Okay, okay. See the console, and you’ll see that the value of our data is updated only inside the callback of nextTick:
const example = Vue.component('example', {
template: '<p>{{ message }}</p>',
data: function () {
return {
message: 'not updated'
}
},
mounted () {
this.message = 'updated'
console.log(
'outside nextTick callback:', this.$el.textContent
) // => 'not updated'
this.$nextTick(() => {
console.log(
'inside nextTick callback:', this.$el.textContent
) // => 'not updated'
})
}
})
new Vue({
el: '#app',
render: h => h(example)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.10/vue.js"></script>
<div id="app"></div>
A use case
Let’s try to define some useful use case for nextTick
.
Imagine that you need to perform some action when a component is mounted. BUT! not only the component. You also need to wait until all its children are mounted and available in the DOM. Damn! Our mounted hook doesn’t guarantee that the whole component tree renders.
If only we had a tool to wait for the next DOM update cycle…
Hahaa:
mounted() {
this.$nextTick(() => {
// The whole view is rendered, so I can safely access or query
// the DOM. ¯\_(ツ)_/¯
})
}
In a nutshell
So: nextTick
is a comfortable way to execute a function after the data has been set, and the DOM has been updated.
You need to wait for the DOM, maybe because you need to perform some transformation or you need to wait for an external library to load its stuff? Then use nextTick.
Some people also use nextTick in their unit tests as a way to ensure that data has been updated. This way, they can test the “updated version” of the component.
Vue.nextTick() or vm.$nextTick()?
Don’t worry. Both are (almost) the same. Vue.nextTick()
refers to the global API method, while vm.$nextTick()
is an instance method. The only difference is that vm.$nextTick
doesn’t accept a context as the second parameter. It is always bound to this
(also known as the instance itself).
A last piece of coolness
Notice that nextTick
returns a Promise
, so we can go full-cool with async/await
and improve the example:
async mounted () {
this.message = 'updated'
console.log(this.$el.textContent) // 'not updated'
await this.$nextTick()
console.log(this.$el.textContent) // 'updated'
}
To make Pranshat's answer about the difference between using nextTick and setTimeout, more explicit, I have forked his fiddle: here
mounted() {
this.one = "One";
setTimeout(() => {
this.two = "Two"
}, 0);
//this.$nextTick(()=>{
//this.two = "Two"
//})}
You can see in the fiddle that when using setTimeOut, the initial data flashes very briefly once the component gets mounted before adapting the change. Whereas, when using nextTick, the data is hijacked, changed, before rendering to the browser. So, the browser shows the updated data without even any knowledge of the old. Hope that clears the two concepts in one swoop.
nextTick allows you to do something after you have changed the data and VueJS has updated the DOM based on your data change, but before the browser has rendered those changed on the page.
Normally, devs use native JavaScript function setTimeout to achieve similar behavior. But, using setTimeout
relinquishes control over to the browser before it gives control back to you via your callback.
Let's say, you changed some data. Vue updates DOM based on the data. Mind you the DOM changes are not yet rendered to the screen by the browser. If you used nextTick
, your callback gets called now. Then, browser updates the page. If you used setTimeout
, your callback would get called only now.
You can visualize this behavior by creating a small component like the following:
<template>
<div class="hello">
{{ msg }}
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
msg: 'One'
}
},
mounted() {
this.msg = 'Two';
this.$nextTick(() => {
this.msg = 'Three';
});
}
}
</script>
Run your local server. You will see the message Three
being displayed.
Now, replace your this.$nextTick
with setTimeout
setTimeout(() => {
this.msg = 'Three';
}, 0);
Reload the browser. You will see Two
, before you see Three
.
Check this fiddle to see it live
That's because, Vue updated the DOM to Two
, gave control to the browser. Browser displayed Two
. Then, called your callback. Vue updated the DOM to Three
. Which the browser displayed again.
With nextTick
. Vue udpated the DOM to Two
. Called your callback. Vue updated the DOM to Three
. Then gave control to the browser. And, the browser displayed Three
.
Hope it was clear.
To understand how Vue implements this, you need to understand the concept of Event Loop and microtasks.
Once you have those concepts clear(er), check the source code for nextTick.
Next Tick basically allows you to run some code, after the vue has re-rendered the component when you have made some changes to the a reactive property (data).
// modify data
vm.msg = 'Hello'
// DOM not updated yet
Vue.nextTick(function () {
// this function is called when vue has re-rendered the component.
})
// usage as a promise (2.1.0+, see note below)
Vue.nextTick()
.then(function () {
// this function is called when vue has re-rendered the component.
})
From the Vue.js Documentation:
Defer the callback to be executed after the next DOM update cycle. Use it immediately after you’ve changed some data to wait for the DOM update.
Read more about it, here.