Explain what happens from a template expression like {{ count }} to a real DOM text node update: template compilation, dependency tracking during render, scheduling/batching, and DOM patching. Mention how Vue handles refs in templates and why interpolation escapes HTML by default.
How does Vue interpolate reactive state into the DOM?
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
The core idea
Vue doesn’t “re-run the whole DOM.” It compiles {{ ... }} into a render function that creates a Virtual DOM (VNode) tree. During render, Vue tracks which reactive properties were read. When one of those properties changes, Vue schedules the component update, re-runs the render function, diffs old vs new VNodes, and patches only the affected DOM nodes (e.g., a single text node).
Stage | What Vue does | Why it matters |
|---|---|---|
1) Compile template |
| Interpolation is not “magic at runtime”; it’s mostly compiler output + runtime patching. |
2) Mount (first render) | Runs render inside a reactive effect. Any reactive read (like | Vue learns exactly which component depends on which reactive keys. |
3) State change | When you mutate reactive state, Vue triggers the dependent render effect(s). | Only components that used that state are scheduled to update. |
4) Batch + schedule | Updates are queued/deduped and flushed in a microtask. | Multiple sync mutations typically lead to one DOM patch per component. |
5) Patch DOM | Re-render → new VNodes → diff/patch updates only the dynamic parts (often a single text node). | Efficient updates without manual DOM manipulation. |
<script setup>
import { ref, nextTick } from 'vue';
const count = ref(0);
async function incTwice() {
count.value++;
count.value++;
// DOM is patched after the batched flush
await nextTick();
// Now the DOM reflects the final value
}
</script>
<template>
<!-- Note: refs are auto-unwrapped in templates -->
<p>Count: {{ count }}</p>
<button @click="incTwice">+2</button>
</template>
What the compiler roughly generates
Vue compiles templates to a render function that produces VNodes. For a dynamic text binding, the runtime can optimize patching using compiler hints (e.g., patch flags). Exact output varies, but the shape looks like this:
// Pseudo-ish compiled shape (not exact Vue output)
import { openBlock, createElementBlock, toDisplayString } from 'vue';
export function render(_ctx) {
return (
openBlock(),
createElementBlock(
'p',
null,
'Count: ' + toDisplayString(_ctx.count),
/* patchFlag */ 1 // TEXT (runtime knows only text needs updating)
)
);
}
Security: interpolation escapes HTML{{ value }} renders text content (escaped). If you need to render HTML, Vue provides v-html, but you must treat it as XSS-sensitive and only use trusted/sanitized content.
<template>
<!-- Escaped: renders literally as "<strong>Hi</strong>" -->
<p>{{ raw }}</p>
<!-- Not escaped: injects HTML into the DOM (danger if untrusted) -->
<p v-html="raw"></p>
</template>
<script setup>
import { ref } from 'vue';
const raw = ref('<strong>Hi</strong>');
</script>
Interview-ready takeaway
Interpolation in Vue is: template compile → render effect tracks reactive reads → state writes trigger scheduled re-render → VDOM diff + patch updates only the dynamic DOM nodes. Templates auto-unwrap refs, and interpolation is HTML-escaped by default.