Vue 52: Performance: v-memo & shallowRef
easy⏱ 5 mincoursevue
v-memo - skip re-rendering a row
v-memo='[dep1, dep2, ...]' tells Vue to memoize a v-for row's subtree and skip it entirely on the next render if none of the listed dependencies changed - even if the parent component re-renders for a completely unrelated reason. It's a surgical optimization for large lists where most rows don't change on any given update.
<div
v-for="item in items"
:key="item.id"
v-memo="[item.active]"
>
<!-- this whole subtree is skipped on re-render
unless item.active changed since last time -->
{{ item.name }} - {{ expensiveFormat(item) }}
</div>
shallowRef - reactivity on purpose, shallow
shallowRef(obj) only tracks reassignment of .value; mutations inside obj trigger nothing. That's exactly what you want for large objects (an external data tree, a big config blob) where making every nested field deeply reactive would be wasted work.
import { shallowRef, triggerRef } from 'vue';
const big = shallowRef({ nested: { count: 0 } });
big.value.nested.count++; // NOT reactive - no re-render
big.value = { nested: { count: 1 } }; // reactive - .value reassigned
triggerRef(big); // force a re-render manually if you must mutate deep
Try it: watch the columns diverge
Click 'Force parent re-render' a few times and watch the no-v-memo column always show the freshest tick on every row, while the v-memo column stays frozen. Then flip a single row's toggle - only that row updates, because only its dependency changed.