Understanding Vue.js nextTick: Mechanism, Usage, and Custom Implementation
This article explains the Vue.js nextTick API, why scrolling to newly added list items may stop prematurely, demonstrates proper usage with scrollIntoView, and provides a hand‑written implementation using MutationObserver to ensure DOM updates complete before executing callbacks.
Introduction – nextTick is a frequently asked interview topic in Vue.js because it reveals important rendering mechanics; many developers struggle to grasp its execution flow.
Problem scenario – A page initially displays 20 li elements. Clicking a button adds 10 more li items and attempts to scroll the last new element into view with element.scrollIntoView({ behavior: 'smooth' }) . The scroll stops halfway because the DOM has not finished updating.
Initial code (incorrect approach)
<template>
<div>
<button @click="updateList">更新列表</button>
<ul>
<li v-for="n in list">{{ n }}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
const list = ref(new Array(20).fill(0))
const updateList = () => {
// push elements one by one
list.value.push(...(new Array(10).fill(1)))
const liItem = document.querySelector('li:last-child')
liItem.scrollIntoView({ behavior: 'smooth' })
}
</script>
<style lang="css" scoped>
li{
height: 100px;
background-color: #21e07a;
margin: 10px;
}
</style>Why it fails – Vue’s component lifecycle runs the click handler before the DOM reflects the newly added li elements. The call to document.querySelector('li:last-child') may retrieve an element that hasn’t been rendered yet, causing the scroll to stop.
Solution with nextTick – By deferring the scroll logic until after Vue finishes updating the DOM, the operation works reliably.
Correct code using nextTick
<script setup>
import { nextTick, ref } from 'vue';
const list = ref(new Array(20).fill(0))
const updateList = () => {
list.value.push(...(new Array(10).fill(1)))
nextTick(() => {
const liItem = document.querySelector('li:last-child')
liItem.scrollIntoView({ behavior: 'smooth' })
})
}
</script>The page now scrolls smoothly to the newly added last item.
Hand‑written nextTick implementation
function myNextTick(fn) {
let app = document.getElementById('app')
// Observe DOM changes
var observerOptions = {
childList: true, // added/removed child nodes
attributes: true, // attribute changes
subtree: true // monitor descendants
};
// Create a MutationObserver that calls fn when the DOM update finishes
let observer = new MutationObserver((el, obs) => {
fn()
})
observer.observe(app, observerOptions)
}This custom myNextTick uses the native MutationObserver to watch for DOM mutations on the element with id app . When the observed changes match the specified options, the callback runs, ensuring the supplied function executes only after the DOM has been updated.
Conclusion – Using Vue’s built‑in nextTick (or a hand‑rolled version based on MutationObserver ) guarantees that DOM‑dependent logic runs at the correct moment, preventing issues like incomplete scrolling.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.