Вычисляемые свойства
Вычисляемое свойство — значение, которое Vue получает из другого состояния и пересчитывает, когда это состояние меняется. Например, число невыполненных задач зависит от списка задач, и хранить его отдельно не нужно.
Функция computed
В этом уроке задачи — объекты с полями id, text и done:
<!-- src/App.vue -->
<script setup>
import { ref, computed } from 'vue'
const todos = ref([
{ id: 1, text: 'Купить хлеб', done: true },
{ id: 2, text: 'Позвонить Анне', done: false },
{ id: 3, text: 'Написать отчёт', done: false },
])
const remaining = computed(() => {
return todos.value.filter((todo) => !todo.done).length
})
</script>
<template>
<p>Осталось задач: {{ remaining }}</p>
</template>На странице появится «Осталось задач: 2». computed принимает функцию, которая возвращает значение, и создаёт объект, похожий на ref: в шаблоне — просто remaining, в скрипте — remaining.value.
Пересчёт
Vue запоминает, какие реактивные данные прочитала функция. Когда они меняются, значение пересчитывается само:
<script setup>
import { ref, computed } from 'vue'
const todos = ref([
{ id: 1, text: 'Купить хлеб', done: false },
{ id: 2, text: 'Позвонить Анне', done: false },
])
const remaining = computed(() => todos.value.filter((t) => !t.done).length)
function finishFirst() {
todos.value[0].done = true
}
</script>
<template>
<p>Осталось задач: {{ remaining }}</p>
<button @click="finishFirst">Выполнить первую</button>
</template>Сначала страница показывает «Осталось задач: 2», после клика — «1».
Отфильтрованный список
Чаще всего computed используют для списков, которые показываются в другом виде:
<script setup>
import { ref, computed } from 'vue'
const todos = ref([
{ id: 1, text: 'Купить хлеб', done: true },
{ id: 2, text: 'Позвонить Анне', done: false },
])
const onlyActive = ref(false)
const visibleTodos = computed(() => {
return onlyActive.value
? todos.value.filter((t) => !t.done)
: todos.value
})
</script>visibleTodos зависит и от списка, и от флага onlyActive. Вывести такой список на страницу поможет директива v-for из урока про списки.
Чем computed лучше функции
Тот же результат даёт функция, вызванная в шаблоне: {{ countRemaining() }}. Разница в кешировании:
| Функция | computed | |
|---|---|---|
| Когда выполняется | При каждой перерисовке | Только при изменении зависимостей |
| Запись в шаблоне | countRemaining() | remaining |
Если на странице меняется что-то, не связанное с задачами, функция всё равно отработает заново, а computed вернёт сохранённое значение.
Частая ошибка
Менять состояние внутри computed:
<script setup>
const sorted = computed(() => todos.value.sort((a, b) => a.id - b.id))
</script>Метод sort переставляет элементы исходного массива — функция вычисления меняет данные, от которых сама зависит. Вычисляемое свойство должно только читать и возвращать. Сортируйте копию: [...todos.value].sort(...) или todos.value.toSorted(...).