List Rendering Caveats
You’ve already seen how to render lists using the v-for directive. Here are some key points to keep in mind about list rendering.
Array Change Detection
Mutation Methods
Vue detects changes when a reactive array is modified using these mutation methods:
push()pop()shift()unshift()splice()sort()reverse()
Using these methods triggers automatic DOM updates.
Replacing an Array
Non-mutating methods like filter(), concat() and slice() do not modify the original array, but return a new array. When using these, replace the old array with the new array:
// `items` is a ref with array value
items.value = items.value.filter((item) => item.message.match(/Foo/))You might think this will cause Vue to throw away the existing DOM and re-render the entire list - luckily, that is not the case. Vue implements some smart heuristics to maximize DOM element reuse, so replacing an array with another array containing overlapping objects is a very efficient operation.
Displaying Filtered/Sorted Results
Sometimes you may want to show a filtered or sorted view without changing the original array. The best approach in this case is to use a computed property:
<script setup>
import { computed, ref } from 'vue'
const numbers = ref([1, 2, 3, 4, 5])
const evenNumbers = computed(() => {
return numbers.value.filter((n) => n % 2 === 0)
})
</script>
<template>
<li v-for="n in evenNumbers" :key="n">{{ n }}</li>
</template>In situations where computed properties are not feasible (e.g. inside nested v-for loops), you can use a method:
<script setup>
import { ref } from 'vue'
const sets = ref([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]
])
function even(numbers) {
return numbers.filter((number) => number % 2 === 0)
}
</script>
<template>
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)" :key="n">{{ n }}</li>
</ul>
</template>Be careful with reverse() and sort() in a computed property! These two methods will mutate the original array, which should be avoided in computed getters. To avoid this, create a copy first:
- return numbers.reverse()
+ return [...numbers].reverse()