Frontend Development 6 min read

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.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding Vue.js nextTick: Mechanism, Usage, and Custom Implementation

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.

JavaScriptMutationObserverVue.jsDOMnextTick
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.