Vue v-memo: skipping DOM patch work
- Last updated
- Prerequisites:
- Vue template basics
- Basic understanding of the virtual DOM patch process
- vue
- v-memo
- rendering
- virtual-dom
- patch
- performance
Read at your depth
The practical view
v-memo="[deps]" tells Vue: if every value in the deps array is identical (Object.is) since the last render, reuse the rendered virtual nodes of this block and skip the diff/patch entirely. Typical usage: v-for with v-memo="[item.id, item.updatedAt]" so a row only re-renders when its own data changed: <div v-for="item in items" :key="item.id" v-memo="[item.id, item.updatedAt]">. The deps array is compared with shallow equality against the previous render's values. When a dependency changes, the whole block re-renders and the memo caches the new values.
The same idea in other frameworks
// memo() on the row component compares props shallowly
const Row = memo(RowView);
// or skip work in the parent with useMemo for the list// Angular: track in @for + OnPush; rows only re-check
// when their signals/props change<div v-for="item in items" :key="item.id"
v-memo="[item.id, item.updatedAt]">…</div>// Svelte compiles per-component granular updates —
// no manual row memoization neededLegacy vs modern
Large list without v-memo vs with v-memo
Without v-memo every render re-diffs all rows; with v-memo each row costs one shallow compare of its memo deps when nothing changed.
<div v-for="item in items" :key="item.id"> <!-- ❌ OLD: no v-memo → every row re-diffs each tick -->
<p>{{ item.title }}</p>
</div><div v-for="item in items" :key="item.id"
v-memo="[item.id, item.likes]" <!-- ✅ NEW: skip patch when [id, likes] unchanged -->
<p>{{ item.title }}</p>
</div>Interview gotchas
Context
Interviewers use this to check whether the candidate understands the two bailout levels in Vue: component props comparison vs template-block memo.
The mechanical answer
v-memo skips the vnode diff for a template block; memoized components skip the whole component render when props are shallowly equal. If the row itself is a component with expensive setup/effects, memo() on the component is the better lever because it avoids re-running the render function and lifecycle entirely. v-memo shines for large flat lists of cheap rows where component overhead per row would itself be wasteful. The wrong use is putting v-memo around a block that reads many reactive sources — the deps array grows, the compare cost approaches the patch cost, and you risk stale output if you miss a source.
Trap
The trap answer is 'v-memo is like memo()'. They operate at different layers — one is a template patch optimization, the other is a component render bailout — and v-memo has a correctness hazard memo() does not: memo() compares props automatically, while v-memo trusts your deps array completely. Missing a dependency silently freezes that part of the UI, which is the failure interviewers want you to name.
Context
This targets mechanical understanding of the renderer: does the candidate know the difference between vnode creation, diffing, and DOM patching?
The mechanical answer
When isMemoSame returns true, the renderer returns the old block vnode and skips the entire mount/patch branch for that subtree: no new vnodes are created, the diff (patchChildren with keyed or unkeyed comparison) never runs, and no DOM insert/update/remove is performed. The vnode is also marked so nested dynamic children are not re-traversed. The one cost that remains is the deps comparison itself — a shallow loop of Object.is over the array — which is O(deps) and trivially cheap. So a 1000-row list with one changed row costs 999 small array compares plus one real patch, versus 1000 full row patches.
Trap
The classic misunderstanding is that v-memo 'prevents re-renders of the component'. The component's render function still runs on parent updates (it must, to evaluate the deps array); only the subtree patch is skipped. Another trap: claiming it skips the reactive effect — v-memo does not change reactivity at all; it changes the renderer's patch decision. Candidates who say 'the reactive effect doesn't run' reveal they conflate the render/patch pipeline with reactivity tracking.