Перейти к содержимому
Тема 4 из 5
Теория

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.

Полное имя

Лёгкая+10 XP

В компоненте FullName есть два ref: first и last. Создай computed с именем full: имя и фамилия через пробел, без лишних пробелов, если одно из них пустое. Покажи его в <p>{{ full }}</p> и верни из setup.

"Ada", "Lovelace"  →  Ada Lovelace
"Ada", ""          →  Ada

Подключи коннектор, чтобы решать задачи

Код задач выполняется на твоём компьютере — так быстрее и надёжнее, чем в браузере. Для этого нужна бесплатная программа-коннектор CodeWithMe. Подключить её нужно один раз.

Ищем коннектор на этом компьютере…

  1. 1
    Скачай коннектор для своей системы (Windows, macOS или Linux).Скачать коннекторНа странице загрузки выбери файл со своей системой в названии, например windows-amd64.
  2. 2Запусти его и выбери папку, где будут лежать твои решения. Python и Node.js он поставит туда сам, когда понадобится.
  3. 3
    Введи ниже код из 6 цифр — он написан в окне коннектора («Код для сайта CodeWithMe»). Если браузер спросит про доступ к локальной сети — разреши.

Коннектор открытый (исходный код на GitHub), работает только на твоём компьютере и выполняет код лишь после ввода кода сопряжения.