Skip to the solution
MediumFrontend9 min read

What is nextTick in Vue?

128 views

The problem

Question presented to candidate: "After I push an item to a list in a click handler, list.children.length still shows the old count. What is going on, what does nextTick do about it, and where exactly does a nextTick callback run compared with a Promise.then or a setTimeout?"

What a strong answer should cover:

  • Vue batches DOM updates: a reactive write queues a job, and the scheduler flushes the queue in a microtask after the current synchronous code.
  • nextTick() returns the promise for that flush; await nextTick() (or a callback) runs after the DOM has been patched.
  • Typical uses: measuring, scrolling or focusing an element right after a state change, and tests (Vue Test Utils' trigger() returns nextTick()).
  • Ordering detail: a nextTick registered before any write in that tick does not wait for a later flush, and Promise.then callbacks queued after the write can run before a later nextTick callback. setTimeout(fn, 0) runs after all of them.
  • Alternatives: flush: 'post' watchers, watchPostEffect and onUpdated for reacting to every update.
  • In the Options API it is this.$nextTick(), with this bound to the instance.

Clarifying questions expected:

  • "Is the goal to read the DOM once after a specific change, or to react after every update?"
  • "Is this in a component or in a test?"

Code / implementation expected: Yes β€” a handler that logs the DOM before and after await nextTick().

  • nexttick
  • reactivity

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read Β· 9 sections

Read the code

VueData vs DOM before and after await nextTick()
<script setup>
import { ref, nextTick, useTemplateRef } from "vue";

const items = ref(["first"]);
const list = useTemplateRef("list");
const count = () => list.value.children.length; // how many <li> the DOM really has

async function add() {
  items.value.push("item " + (items.value.length + 1));
  console.log(`after push:      data has ${items.value.length}, DOM has ${count()}`);

  await nextTick(); // wait for Vue to flush its update queue
  console.log(`after nextTick:  data has ${items.value.length}, DOM has ${count()}`);

  // Now it is safe to measure or focus the new element.
  list.value.lastElementChild.scrollIntoView?.();
}
</script>

<template>
  <ul ref="list">
    <li v-for="item in items" :key="item">{{ item }}</li>
  </ul>
  <button @click="add">Add</button>
</template>
VueOrdering lab: nextTick vs Promise.then vs setTimeout vs watchers
<script setup>
import { ref, nextTick, watch, onUpdated, useTemplateRef } from "vue";
const n = ref(0);
const p = useTemplateRef("p");
const dom = () => p.value.textContent;

watch(n, () => console.log(`  pre watcher        DOM="${dom()}"`));
watch(n, () => console.log(`  post watcher       DOM="${dom()}"`), { flush: "post" });
onUpdated(() => console.log(`  onUpdated          DOM="${dom()}"`));

function run() {
  console.log("A. nextTick registered BEFORE the change");
  nextTick(() => console.log(`  nextTick (early)   DOM="${dom()}"`));
  setTimeout(() => console.log(`  setTimeout 0       DOM="${dom()}"`), 0);
  Promise.resolve().then(() => console.log(`  Promise.then early DOM="${dom()}"`));

  n.value++;
  console.log(`  sync after n++     DOM="${dom()}"`);

  nextTick(() => console.log(`  nextTick (late)    DOM="${dom()}"`));
  Promise.resolve().then(() => console.log(`  Promise.then late  DOM="${dom()}"`));
  const r = nextTick();
  console.log(`  nextTick() returns a Promise: ${r instanceof Promise}`);
}
</script>
<template><p ref="p">n={{ n }}</p><button @click="run">go</button></template>

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 67 of 92 in Vue.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Vue.js questions
Up nextMedium

When should you use readonly, markRaw, and toRaw in Vue reactivity?

Continue