Below is a Vue component for you to consider:
- When you click the Update button, how many times will Vue update your actual DOM (the
h1
element)?
- Although we know that eventually the
h1
element will display 2, will it first display 1 before displaying 2?
- You might argue that the DOM can be changed multiple times before actually re-rendering, so let's ask this: will the
h1
element ever be in 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 unsure, try the following variation of the component and observe the result:
<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>
See it in action.
This example demonstrates how Vue "buffers changes" to ensure components are "updated once" regardless of how many "state changes" occur. It may not always involve two consecutive increments like in this case, but handling complex state changes without overlapping can be challenging. State mutations happening at different points in the codebase can trigger further updates through computed properties and watchers.
- Computed properties will update.
- Watchers will fire.
- Both can trigger additional computed properties and watchers.
Binding state to templates isn't straightforward due to Vue's reactive programming approach. While your template is declarative, Vue has to imperatively update it. Making synchronous modifications to the real DOM with every reactive state change is costly and inefficient.
Vue synchronously applies state changes to the virtual dom and syncs it with the real dom when all state modifications are complete. This typically occurs after exiting the update
method.
Internally, Vue uses microtask queue to schedule DOM patching. Upon the first state mutation, Vue schedules a flush job via a microtask queue handled by Promise
. The micro task executes only when the current Javascript call stack is empty.
nextTick
dispatches a micro task directly to the queue, ensuring your callback runs after other micro tasks, usually those related to DOM operations dispatched by Vue. In Node.js, this process is called nextTick
.
When should you use nextTick
? Remember that the DOM doesn't update synchronously while changing states, requiring the use of nextTick
to access the resulted DOM after state changes. Common scenarios include focusing elements conditionally rendered based on state changes, as the template ref won't have a value until Vue patches the DOM.