Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Enforce Vue 3 best practices—Composition API, script setup, TypeScript, component boundaries, and reactivity patterns
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/perf-v-once-v-memo-directives.md
1---2title: Use v-once and v-memo to Skip Unnecessary Updates3impact: MEDIUM4impactDescription: v-once skips all future updates for static content; v-memo conditionally memoizes subtrees5type: efficiency6tags: [vue3, performance, v-once, v-memo, optimization, directives]7---89# Use v-once and v-memo to Skip Unnecessary Updates1011**Impact: MEDIUM** - Vue re-evaluates templates on every reactive change. For content that never changes or changes infrequently, `v-once` and `v-memo` tell Vue to skip updates, reducing render work.1213Use `v-once` for truly static content and `v-memo` for conditionally-static content in lists.1415## Task List1617- Apply `v-once` to elements that use runtime data but never need updating18- Apply `v-memo` to list items that should only update on specific condition changes19- Verify memoized content doesn't need to respond to other state changes20- Profile with Vue DevTools to confirm update skipping2122## v-once: Render Once, Never Update2324**BAD:**25```vue26<template>27<!-- BAD: Re-evaluated on every parent re-render -->28<div class="terms-content">29<h1>Terms of Service</h1>30<p>Version: {{ termsVersion }}</p>31<div v-html="termsContent"></div>32</div>3334<!-- This content NEVER changes, but Vue checks it every render -->35<footer>36<p>Copyright {{ copyrightYear }} {{ companyName }}</p>37</footer>38</template>39```4041**GOOD:**42```vue43<template>44<!-- GOOD: Rendered once, skipped on all future updates -->45<div class="terms-content" v-once>46<h1>Terms of Service</h1>47<p>Version: {{ termsVersion }}</p>48<div v-html="termsContent"></div>49</div>5051<!-- v-once tells Vue this never needs to update -->52<footer v-once>53<p>Copyright {{ copyrightYear }} {{ companyName }}</p>54</footer>55</template>5657<script setup>58// These values are set once at component creation59const termsVersion = '2.1'60const termsContent = fetchedTermsHTML61const copyrightYear = 202462const companyName = 'Acme Corp'63</script>64```6566## v-memo: Conditional Memoization for Lists6768**BAD:**69```vue70<template>71<!-- BAD: All items re-render when selectedId changes -->72<div v-for="item in list" :key="item.id">73<div :class="{ selected: item.id === selectedId }">74<ExpensiveComponent :data="item" />75</div>76</div>77</template>78```7980**GOOD:**81```vue82<template>83<!-- GOOD: Items only re-render when their selection state changes -->84<div85v-for="item in list"86:key="item.id"87v-memo="[item.id === selectedId]"88>89<div :class="{ selected: item.id === selectedId }">90<ExpensiveComponent :data="item" />91</div>92</div>93</template>9495<script setup>96import { ref } from 'vue'9798const list = ref([/* many items */])99const selectedId = ref(null)100101// When selectedId changes:102// - Only the previously-selected item re-renders (selected: true -> false)103// - Only the newly-selected item re-renders (selected: false -> true)104// - All other items are SKIPPED (v-memo values unchanged)105</script>106```107108## v-memo with Multiple Dependencies109110```vue111<template>112<!-- Re-render only when item's selection OR editing state changes -->113<div114v-for="item in items"115:key="item.id"116v-memo="[item.id === selectedId, item.id === editingId]"117>118<ItemCard119:item="item"120:selected="item.id === selectedId"121:editing="item.id === editingId"122/>123</div>124</template>125126<script setup>127const selectedId = ref(null)128const editingId = ref(null)129const items = ref([/* ... */])130</script>131```132133## v-memo with Empty Array = v-once134135```vue136<template>137<!-- v-memo="[]" is equivalent to v-once -->138<div v-for="item in staticList" :key="item.id" v-memo="[]">139{{ item.name }}140</div>141</template>142```143144## When NOT to Use These Directives145146```vue147<template>148<!-- DON'T: Content that DOES need to update -->149<div v-once>150<span>Count: {{ count }}</span> <!-- count won't update! -->151</div>152153<!-- DON'T: When child components have their own reactive state -->154<div v-memo="[selected]">155<InputField v-model="item.name" /> <!-- v-model won't work properly -->156</div>157158<!-- DON'T: When the memoization benefit is minimal -->159<span v-once>{{ simpleText }}</span> <!-- Overhead not worth it -->160</template>161```162163## Performance Comparison164165| Scenario | Without Directive | With v-once/v-memo |166|----------|-------------------|-------------------|167| Static header, parent re-renders 100x | Re-evaluated 100x | Evaluated 1x |168| 1000 items, selection changes | 1000 items re-render | 2 items re-render |169| Complex child component | Full re-render | Skipped if memoized |170171## Debugging Memoized Components172173```vue174<script setup>175import { onUpdated } from 'vue'176177// This won't fire if v-memo prevents update178onUpdated(() => {179console.log('Component updated')180})181</script>182```183