0👍
- what is meant by componenent is updated only once ? and when this only once update is launched ?
Lets say you have 3 variables:
let age
let home
let name
And you change all of them at once. It would be very inefficient if you need to do 3 updates at once Instead of updating the DOM 3x it will save the state until the next tick occure and update it only 1x.
- what are the case i need to use nextTick ?
Vue.component('popup', {
template: `<div style="border: 1px solid gray" ref="popup" tabindex="0" @blur="close">
<p>popuup</p>
</div>`,
methods: {
close() {
this.$emit("close")
},
},
created(){
this.$refs.popup.focus()
}
})
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
open: false
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button @click="open = true">open</button>
<popup @close="open = false" v-if="open"></popup>
</div>
Here an example: Here i have an popup item. Now i want whenever i click outside the box, to close it. For this i need to focus it on creation time so the blur even gets triggered when i click outside. The problem here is that the DOM element is not created yet. It will throw an error
The solution is to use $nextTick()
so it actually waits until the DOM gets mounted and then this code will actually work.
Vue.component('popup', {
template: `<div style="border: 1px solid gray" ref="popup" tabindex="0" @blur="close">
<p>popuup</p>
</div>`,
methods: {
close() {
this.$emit("close")
},
},
created(){
this.$nextTick(() => {
this.$refs.popup.focus()
})
}
})
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
open: false
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button @click="open = true">open</button>
<popup @close="open = false" v-if="open"></popup>
</div>
0👍
Ah, good questions. An update cycle in Vue goes like this:
- a change in data is detected (this ultimately triggers the next DOM update)
- all affected data is updated (watchers are executed, computed properties are updated, binds are reevaluated and so on)
- the DOM is updated to show the changes (since all changes are handled together, only one update is needed)
- wait for the next change
nextTick()
is used to perform an action after the current cycle has concluded and DOM changes have been applied.
A typical case for nextTick()
is when you enable an element by changing a condition in a v-if
and want to scroll to it. If you run scrollTo()
the moment you change the condition, the element will not be there (or at least not be fully rendered, causing the scroll to miss its actual position). But if you do it in nextTick()
, it works.
0👍
Consider the below Vue component:
- How many times will Vue update your actual DOM (the
h1
element) when you click the Update button? - We all know that eventually the
h1
element will display 2, but will it display 1 first before it displays 2? - You might argue that you can still change DOM many times before it actually re-renders, which is true, so let’s put it in this way: will the
h1
element ever be in such a state where its innerHTML == "1"?
<script setup>
import { ref } from 'vue'
const counter = ref(0)
const update = () => {
counter.value = counter + 1
counter.value = counter + 1
}
</script>
<template>
<h1>{{ counter }}</h1>
<button @click="update">Update</button>
</template>
If you are not sure, write the component in this way and see the result yourself:
<script setup>
import { ref } from 'vue'
const header = ref();
const counter = ref(0)
const update = () => {
counter.value = Number(header.value.innerHTML) + 1
counter.value = Number(header.value.innerHTML) + 1
}
</script>
<template>
<h1 ref="header">{{ counter }}</h1>
<button @click="update">Update</button>
</template>
This is a very simple example to demonstrate what it means when Vue says it "buffers changes" so that components only get "updated once" no matter how many "state changes" you have made.
Obviously in this example you don’t have to do two consecutive increments, but in reality, it is much harder to layout complicated state changes in strictly non-overlapping fashion. On the one hand, not all state mutations happen at a single location in your source code; and on the other hand, simple state changes easily trigger further state changes:
- computed properties will update
- watches will fire
- they all can trigger further computed properties and watches
State to template binding isn’t trivial neither. It all comes down to the fact that Vue is dealing with reactive programming: your template is declarative, but Vue has to update your template imperatively.
Synchronously modifying the real DOM as you make changes to every individual reactive state field is not only expensive, but also wasteful sometimes.
Vue only applies state changes synchronously to the virtual dom, and Vue sync the virtual dom with your real dom when you are done modifying the states. In this case it is roughly when you exit the update
method.
Internally Vue uses microtask queue to schedule the dom patching. The moment you make the first state mutation, Vue will schedule a flush job onto the microtask queue, through Promise
. Micro task will not be executed until there is nothing else running, in other words, until the current js call stack is empty.
nextTick
is such a method that directly dispatches a micro task to the micro queue, so that your callback will be called after all the other micro tasks (usually the Vue dispatches DOM operations). In fact, in nodejs the method to dispatch micro task is called exactly nextTick
(google nodejs nextTick please).
So when do you want to use nextTick
? Well, the key thing to remember is that DOM is not changed synchronously while you are changing states, so if you want access the DOM resulted from your state change, you have to use nextTick
. Basically deferring yourself to the end of the queue so that Vue can patch the DOM first. Common use cases include e.g. focus an element that is conditionally rendered by your state change (to focus the element you need to have a template ref, but the template ref won’t have value until Vue patches the DOM).
- [Vuejs]-After page reload vue router push doesn't work
- [Vuejs]-Intercepting queried params in vue router