Интервью-вопрос
Что такое watch
watch во Vue запускает код при изменении реактивного источника. Важно объяснить, что это инструмент для побочных эффектов, а не замена computed.
- Добавлен
- Редакция
Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.
Мини-квиз
Проверка перед разбором
Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.
Вопрос 1 из 50 правильно
Разбор
Разобраться, а не зазубрить
Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.
Базовая идея
watch во Vue наблюдает за реактивным источником и вызывает обработчик, когда значение меняется. В обработчик обычно приходят новое и старое значение, поэтому вы можете сравнить состояние до и после изменения.
Главное в ответе: watch нужен для побочного эффекта. Он не нужен, чтобы просто получить новую строку, число или объект для шаблона. Он нужен, когда изменение данных должно запустить действие: запрос, запись в хранилище, валидацию, аналитику или синхронизацию с внешним состоянием.
Как выбрать между watch и computed
На интервью удобно сказать так: computed отвечает на вопрос, какое значение получается из текущих данных. watch отвечает на вопрос, что нужно сделать, когда данные изменились.
Если вы делаете fullName из имени и фамилии, это computed. Если при смене userId нужно загрузить профиль, это watch. Такая граница показывает, что вы не используете watch как универсальный инструмент для любой реакции.
Как выбрать инструмент
Выбирайте computed.Выбирайте watch.Часто достаточно обработчика события или v-model.Используйте watch с массивом источников.Пример безопасного watch для запроса
Типичный практический пример: компонент получает userId, и при его изменении нужно загрузить пользователя. Рискованный вариант просто пишет ответ каждого запроса в состояние. Если пользователь быстро переключит id, медленный старый ответ может прийти позже и показать не того пользователя.
Более безопасный вариант в Composition API использует cleanup и отменяет прошлый запрос.
<script setup>
import { ref, watch } from 'vue';
const userId = ref('1');
const user = ref(null);
const loading = ref(false);
const error = ref(null);
watch(
userId,
async (id, _oldId, onCleanup) => {
const controller = new AbortController();
onCleanup(() => controller.abort());
loading.value = true;
error.value = null;
try {
const response = await fetch(`/api/users/${id}`, {
signal: controller.signal,
});
if (!response.ok) {
throw new Error('Failed to load user');
}
user.value = await response.json();
} catch (e) {
if (e.name !== 'AbortError') {
error.value = e;
}
} finally {
if (!controller.signal.aborted) {
loading.value = false;
}
}
},
{ immediate: true },
);
</script>Здесь immediate: true нужен для первой загрузки, а onCleanup защищает UI от устаревшего запроса. Отдельные loading и error не дают экрану зависнуть в непонятном состоянии. Если API нельзя отменить, можно хранить текущий id запроса и перед записью результата проверять, что он все еще актуален.
- 1Следить за конкретным id или фильтром
- 2Ставить loading перед запросом
- 3Показывать error или empty state вместо молчаливой пустоты
- 4Отменять или игнорировать устаревший запрос
- 5Писать результат только если он еще актуален
- 1Следить за большим объектом целиком
- 2Запускать запрос на каждое мелкое изменение
- 3Не делать cleanup
- 4Не различать загрузку, ошибку и пустой результат
- 5Разрешать старому ответу перезаписать новый UI
Несколько источников и точная зависимость
Если эффект зависит от нескольких значений, в Composition API можно наблюдать массив источников. Это лучше, чем делать несколько почти одинаковых watcher.
watch([categoryId, page, sort], ([newCategoryId, newPage, newSort]) => {
loadProducts({
categoryId: newCategoryId,
page: newPage,
sort: newSort,
});
});Практический вывод: перечисляйте ровно те зависимости, которые запускают эффект. Watcher на большое состояние целиком чаще приводит к лишним запросам, сложной отладке и неожиданным срабатываниям.
Deep watching без магии
deep: true нужен, когда вы наблюдаете объект целиком и хотите реагировать на изменения внутри него. Но это не настройка на всякий случай. Чем больше объект, тем выше риск лишних срабатываний и затрат на отслеживание.
Часто лучше следить за конкретным полем или геттером:
watch(
() => user.value.profile.email,
(email) => {
validateEmail(email);
},
);Так код честно показывает, от чего зависит эффект. Это проще читать, проще тестировать и сложнее случайно сломать при расширении объекта.
Как сформулировать ответ на интервью
Хороший короткий ответ может звучать так:
watch во Vue отслеживает изменение реактивного источника и запускает обработчик. Я использую его для побочных эффектов, например для запроса при смене id, валидации или синхронизации с URL. Если нужно просто получить производное значение для шаблона, я выберу computed. Для async-watch важно не забыть про отмену или игнорирование устаревших запросов.
Эта формулировка закрывает определение, отличие от computed и практический риск. Если у вас есть опыт с Vue 2 Options API, можно добавить, что идея та же, но синтаксис отличается: в Options API watcher описывают в секции watch, а в Composition API используют функцию watch.
Частые ошибки
Где обычно ошибаются
Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.
- 1
Заменять computed на watch
Если значение просто вычисляется из других данных,watchсоздаст лишнее состояние и больше мест для ошибки. Например, можно забыть обновить поле при одном из изменений. Безопаснее сделатьcomputed, потому что Vue сам пересчитает значение по зависимостям. - 2
Ставить deep: true без причины
Глубокий watcher реагирует на вложенные изменения и может стать дорогим на больших объектах. Еще он часто скрывает плохую модель данных, когда компонент следит за всем объектом вместо нужного поля. Лучше наблюдать конкретный источник, например() => user.value.name. - 3
Не защищать async-watch от гонок
Если пользователь быстро меняет фильтр, старый запрос может завершиться позже нового и перезаписать актуальные данные. В ответе стоит сказать про cleanup,AbortControllerили проверку актуального значения перед записью в состояние. Для строки поиска добавьте debounce, иначе UI будет дергаться, а клиент отправит лишние запросы. - 4
Следить за слишком широким источником
Watcher на весь объект будет срабатывать чаще, чем нужно, и может запускать лишние запросы или валидацию. Это ухудшает производительность и усложняет отладку. Лучше выбрать минимальную зависимость, от которой реально зависит побочный эффект. - 5
Забывать про начальный запуск
По умолчаниюwatchсработает после изменения, а не сразу. Если данные нужно загрузить по текущемуidпри открытии компонента, добавьтеimmediate: trueили вызовите загрузку отдельно. Иначе экран может остаться пустым до первого изменения.
Follow-up
Что могут спросить дальше
Короткие ответы на вопросы, которыми проверяют понимание watch, computed и побочных эффектов во Vue.
Живые ответы
Видео с похожим вопросом
Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.
Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.
Какие библиотеки часто используешь 😎
В ответе важно назвать не просто список библиотек, а задачи, ради которых вы их выбираете, и ограничения этих решений. Разбираем, как показать опыт без хаотичного перечисления пакетов.
Что такое вычисляемые свойства 😎
Вычисляемые свойства во Vue возвращают синхронно рассчитанное значение на основе реактивных зависимостей и кэшируются до их изменения. Разбираем, когда использовать computed, чем он отличается от methods и watch, и какие ошибки ломают реактивность.