computed и watch
Вычисляемые значения
Часто на экране нужно не само состояние, а что-то, посчитанное из него: полное имя из имени и
фамилии, сумма корзины, отфильтрованный список, «можно ли отправить форму». Писать это выражение
прямо в шаблоне неудобно, а хранить в отдельном ref и обновлять вручную — источник ошибок.
Для этого во Vue есть computed:
const { ref, computed } = Vue;
const price = ref(100);
const qty = ref(3);
const total = computed(() => price.value * qty.value);
console.log(total.value); // 300
qty.value = 5;
console.log(total.value); // 500 — пересчиталось само
computed получает функцию-«формулу». Vue запоминает, от каких реактивных данных она зависит
(price и qty), и пересчитывает результат, только когда они меняются. В шаблоне — без .value:
{{ total }}.
computed или функция?
В прошлой теме мы вызывали в шаблоне функции: {{ price() }}. Разница в кэше:
- функция выполняется при каждой перерисовке компонента;
computedхранит результат и пересчитывает его, только если изменились зависимости.
Для дешёвых выражений разницы почти нет, а для фильтрации больших списков, сортировки, сложных
подсчётов computed заметно экономнее. Поэтому производные данные во Vue принято делать через
computed.
const todos = ref([...]);
const filter = ref("all");
const visible = computed(() => {
if (filter.value === "done") return todos.value.filter((t) => t.done);
if (filter.value === "active") return todos.value.filter((t) => !t.done);
return todos.value;
});
const left = computed(() => todos.value.filter((t) => !t.done).length);
Функция внутри computed должна только считать и возвращать: не менять другие данные, не делать
запросов. Для действий есть watch.
watch — следить за изменениями
watch вызывает функцию, когда меняется источник. Это место для побочных эффектов: сохранить в
localStorage, отправить запрос, записать в журнал.
const { ref, watch } = Vue;
const theme = ref(localStorage.getItem("theme") ?? "light");
watch(theme, (newValue, oldValue) => {
localStorage.setItem("theme", newValue);
console.log(`Тема: ${oldValue} → ${newValue}`);
});
Источник — ref, computed, реактивный объект или функция-геттер:
watch(() => user.age, (age) => ...).
Полезные настройки:
watch(query, search, { immediate: true }); // вызвать сразу, не дожидаясь изменения
watch(settings, save, { deep: true }); // следить за вложенными полями объекта
computed vs watch
| Нужно | Используй |
|---|---|
| значение, посчитанное из других данных | computed |
| сделать что-то, когда данные изменились | watch |
Если ловишь себя на коде «в watch записываю результат в другой ref» — почти наверняка это должен
быть computed.
Итог
computed(() => формула)— производное значение с кэшем; в шаблоне без.value.- Внутри
computedтолько считаем, без побочных эффектов. watch(источник, (новое, старое) => ...)— реакция на изменение: сохранение, запросы, журнал.- Опции
watch:immediate,deep.