VueJS - Rendering
VueJS - Conditional and List Rendering
Section titled “VueJS - Conditional and List Rendering”This chapter covers how to conditionally render elements based on JavaScript expressions and how to render lists of items dynamically in Vue.
Conditional Rendering
Section titled “Conditional Rendering”Vue provides directives like v-if, v-else, v-else-if, and v-show to control whether elements are rendered or displayed based on the truthiness of JavaScript expressions.
v-if, v-else, v-else-if
Section titled “v-if, v-else, v-else-if”v-if conditionally renders an element or a template fragment. The element and its content will only be rendered if the directive’s expression evaluates to a truthy value. v-else provides an ‘else’ block for v-if, and v-else-if provides an ‘else if’ block.
Crucially, v-else and v-else-if elements must immediately follow a v-if or v-else-if element, respectively.
Example: Using v-if, v-else-if, v-else
Section titled “Example: Using v-if, v-else-if, v-else”<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 Conditional Rendering</title> <script src="https://unpkg.com/vue@3"></script> <style> button { margin: 5px; padding: 8px 12px; } p { margin-top: 10px; font-weight: bold; } </style></head><body> <div id="app"> <button @click="score = 95">Set Score High</button> <button @click="score = 70">Set Score Medium</button> <button @click="score = 40">Set Score Low</button> <button @click="score = null">Clear Score</button>
<p v-if="score === null"> Score not set. </p> <p v-else-if="score >= 90"> Grade: A (Score: {{ score }}) </p> <p v-else-if="score >= 60"> Grade: C (Score: {{ score }}) </p> <p v-else> Grade: F (Score: {{ score }}) </p>
<!-- v-if on <template> for grouping --> <template v-if="score !== null && score < 60"> <p style="color: red;">This requires attention!</p> </template>
</div>
<script> const { createApp, ref } = Vue;
createApp({ setup() { const score = ref(null); return { score }; } }).mount('#app'); </script></body></html>In this example:
- We use
refto hold thescore. - Buttons modify the
scorevalue. - The
v-if/v-else-if/v-elsechain displays the appropriate grade based on the score. - Only one block in the chain will be rendered at any time.
- A
<template>tag withv-ifis used to conditionally render a group of elements (in this case, just one paragraph) without rendering an extra wrapper element in the DOM.
Try clicking the buttons. You’ll see the output text change based on the score. Inspect the DOM using browser developer tools: notice how the <p> tags are actually added or removed from the DOM structure as the conditions change.
v-show
Section titled “v-show”v-show also conditionally displays an element based on a truthy/falsy expression. The key difference from v-if is that an element with v-show is always rendered in the DOM. It’s simply toggled using the CSS display property (display: none; when the condition is false).
Example: Using v-show
Section titled “Example: Using v-show”<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 v-show Example</title> <script src="https://unpkg.com/vue@3"></script></head><body> <div id="app"> <button @click="isVisible = !isVisible"> Toggle Visibility (v-show) </button>
<h2 v-show="isVisible" style="color: blue;"> This element uses v-show. It's always in the DOM. </h2>
<button @click="isRendered = !isRendered"> Toggle Rendering (v-if) </button> <h2 v-if="isRendered" style="color: green;"> This element uses v-if. It's added/removed from the DOM. </h2> </div>
<script> const { createApp, ref } = Vue;
createApp({ setup() { const isVisible = ref(true); const isRendered = ref(true); return { isVisible, isRendered }; } }).mount('#app'); </script></body></html>Toggle both buttons and inspect the elements in your browser’s developer tools:
- The
v-showelement (blue text) will always be present in the DOM structure, but it will have an inlinestyle="display: none;"added whenisVisibleisfalse. - The
v-ifelement (green text) will completely disappear from the DOM structure whenisRenderedisfalse.
v-if vs v-show: When to Use Which?
Section titled “v-if vs v-show: When to Use Which?”v-ifhas higher toggle costs because it involves adding/removing elements from the DOM. It also has lower initial render costs because the element isn’t rendered if the condition is initially false. Usev-ifwhen the condition is unlikely to change often, or when you want to ensure the component/element inside is truly destroyed and recreated on toggle.v-showhas lower toggle costs because it only changes CSSdisplay. It has higher initial render costs because the element is always rendered. Usev-showwhen you need to toggle something frequently.
Common Pitfall: v-show does not work on <template> elements, nor does it work with v-else or v-else-if.
List Rendering with v-for
Section titled “List Rendering with v-for”The v-for directive is used to render a list of items based on an array, object, range, or other iterable source.
Syntax
Section titled “Syntax”- On Arrays:
v-for="item in items"orv-for="(item, index) in items" - On Objects:
v-for="value in myObject"orv-for="(value, key) in myObject"orv-for="(value, key, index) in myObject" - On Ranges:
v-for="n in 10"(renders 1, 2, … 10)
Inside the v-for scope, you have full access to parent scope properties and the current item (item, value, n) and optionally its index or key.
Example: Rendering a List of Fruits
Section titled “Example: Rendering a List of Fruits”<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 List Rendering</title> <script src="https://unpkg.com/vue@3"></script> <style> input { margin-bottom: 10px; padding: 5px; } ul { list-style: none; padding: 0; } li { background-color: #eee; margin: 5px; padding: 10px; border-radius: 4px; } li span { font-weight: bold; margin-right: 5px; } </style></head><body> <div id="app"> <input type="text" v-model="newFruit" @keyup.enter="addFruit" placeholder="Enter a fruit and press Enter">
<h2>My Fruits:</h2> <p v-if="fruits.length === 0">No fruits yet!</p> <ul v-else> <!-- Using item and index --> <li v-for="(fruit, index) in fruits" :key="fruit.id"> <span>{{ index + 1 }}.</span> {{ fruit.name }} <button @click="removeFruit(fruit.id)" style="float: right;">X</button> </li> </ul>
<h2>Object Iteration:</h2> <ul> <li v-for="(value, key) in fruitInfo" :key="key"> <span>{{ key }}:</span> {{ value }} </li> </ul>
</div>
<script> const { createApp, ref, reactive } = Vue;
createApp({ setup() { const fruits = ref([ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }, { id: 3, name: 'Orange' } ]); const newFruit = ref(''); let nextId = 4;
const fruitInfo = reactive({ color: 'Red', taste: 'Sweet', season: 'Autumn' });
const addFruit = () => { if (newFruit.value.trim()) { fruits.value.push({ id: nextId++, name: newFruit.value.trim() }); newFruit.value = ''; // Clear input } };
const removeFruit = (idToRemove) => { fruits.value = fruits.value.filter(fruit => fruit.id !== idToRemove); };
return { fruits, newFruit, addFruit, removeFruit, fruitInfo }; } }).mount('#app'); </script></body></html>In this example:
- We use
v-for="(fruit, index) in fruits"to iterate over thefruitsarray. - We display the
index(plus 1 for human-readable numbering) and thefruit.name. - We use
v-for="(value, key) in fruitInfo"to iterate over the properties of thefruitInfoobject. - An input allows adding new fruits to the reactive
fruitsarray, and the list updates automatically.
The Importance of key
Section titled “The Importance of key”When using v-for, it is highly recommended to provide a unique key attribute for each item: :key="uniqueValue". This helps Vue identify each node efficiently, allowing it to reuse and reorder existing elements rather than recreating them from scratch.
Why is key important?
- Performance: Allows Vue’s diffing algorithm to be more efficient when the list changes (items added, removed, or reordered).
- State Preservation: Helps preserve the state of components or elements within the list. Without keys, Vue might reuse an element for a different item, leading to unexpected state.
- Transitions: Essential for applying transitions correctly with
<TransitionGroup>(covered in the Transition & Animation chapter).
Use a unique identifier from your data (like an ID from a database) as the key. Avoid using the loop index as a key if the order of items might change or if items can be added/removed from the middle, as this defeats the purpose of efficient tracking.
Common Pitfall: Forgetting the :key attribute or using a non-unique value (like the index when order changes) can lead to rendering bugs and poor performance.
Using v-for with v-if
Section titled “Using v-for with v-if”It’s generally not recommended to use v-if and v-for on the same element due to implicit precedence which can be confusing (in Vue 3, v-if has higher precedence). Instead, you can achieve conditional list rendering in two main ways:
- Filter the source array: Use a computed property to return a filtered list, then use
v-foron the computed property. - Conditional rendering inside the loop: Place the
v-ifon an inner element (or<template>) inside thev-forloop.
// Option 1: Computed Property (Recommended)const visibleFruits = computed(() => fruits.value.filter(f => f.isVisible));// Template:// <li v-for="fruit in visibleFruits" :key="fruit.id">{{ fruit.name }}</li>
// Option 2: v-if inside v-for// <template v-for="fruit in fruits" :key="fruit.id">// <li v-if="fruit.isVisible">{{ fruit.name }}</li>// </template>Filtering the source data using a computed property is often cleaner and more performant.
Further Reading: Vue’s official documentation covers conditional rendering: https://vuejs.org/guide/essentials/conditional.html and list rendering: https://vuejs.org/guide/essentials/list.html