Gernar
Frontend DeveloperVue.js

Интервью-вопрос

Что такое вычисляемые свойства

Вычисляемые свойства во Vue нужны для синхронных производных значений от реактивного состояния. Главный риск для ответа: спутать computed с методом, watcher или местом для side effects.

Добавлен
Редакция

Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.

🐰0
🥚0

Мини-квиз

Проверка перед разбором

Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.

Вопрос 1 из 50 правильно

Как лучше коротко объяснить computed на интервью?

Вы отвечаете на базовый вопрос про Vue и хотите сразу показать практический смысл.

Варианты ответа

Разбор

Разобраться, а не зазубрить

Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.

Базовая идея

Computed во Vue отвечает на вопрос: какое значение получается из текущего реактивного состояния. Это не команда и не обработчик события, а производное значение.

Например, у вас есть список задач и фильтр. Шаблону не обязательно знать, как именно фильтровать массив. Вы можете дать ему готовое значение:

<script setup>
import { computed, ref } from 'vue';

const query = ref('');
const tasks = ref([
  { id: 1, title: 'Fix search', done: false },
  { id: 2, title: 'Update tests', done: true },
]);

const visibleTasks = computed(() => {
  const text = query.value.trim().toLowerCase();

  return tasks.value.filter((task) =>
    task.title.toLowerCase().includes(text)
  );
});
</script>

Здесь visibleTasks зависит от query и tasks. Пока они не изменились, Vue может вернуть закэшированный результат. Если изменился фильтр или список, значение пересчитается.

Чем computed отличается от methods и watch

Самая частая ловушка на интервью: сказать, что computed это просто метод. Внешне похоже, потому что внутри тоже есть функция, но контракт другой.

Computed используется как значение. Метод используется как действие или вычисление по вызову. Watch используется как реакция на изменение, когда нужно выполнить побочный эффект.

Как выбрать между computed, method и watch

1Нужно синхронно получить значение из reactive state?
Выбирайте computed.
2Нужно выполнить действие при изменении значения?
Выбирайте watch или watchEffect.
3Нужно запустить логику по клику или submit?
Выбирайте метод или обработчик события.
4Значение должно работать с v-model в обе стороны?
Рассмотрите writable computed с get и set.

Если вы объясните выбор через задачу, ответ будет звучать сильнее:

Если мне нужно только показать производное значение в UI, я выберу computed. Если мне нужно что-то сделать при изменении значения, например отправить запрос или записать данные во внешнюю систему, я выберу watch. Если логика запускается по событию пользователя или требует аргументов, подойдет метод.

Почему важно кэширование

Кэширование полезно, когда значение читается несколько раз или расчет не совсем дешевый. Например, фильтрация и сортировка большого списка в шаблоне как метод может выполняться чаще, чем вы ожидаете.

Плохой пример:

<template>
  <UserRow
    v-for="user in getVisibleUsers()"
    :key="user.id"
    :user="user"
  />
</template>

Такой метод может вызываться при каждом рендере. Если внутри тяжелая фильтрация, интерфейс будет делать лишнюю работу. Безопаснее вынести чистое производное значение в computed и читать его как данные.

Важно не обещать, что computed всегда быстрее. Если вычисление простое и вызывается один раз, разницы может не быть. Смысл computed не только в скорости, но и в ясном контракте: это derived state, который зависит от реактивных источников.

Чистота getter и побочные эффекты

Getter computed должен быть предсказуемым. Он читает реактивные зависимости и возвращает результат. Он не должен менять состояние, отправлять запросы, запускать таймеры или писать в браузерные API.

Плохой пример:

const total = computed(() => {
  analytics.track('cart_total_read');
  cartWasRead.value = true;

  return items.value.reduce((sum, item) => sum + item.price, 0);
});

Проблема в том, что простое чтение total теперь меняет приложение и отправляет аналитику. Это может сработать несколько раз, сработать не тогда, когда вы ожидаете, или спровоцировать лишний рендер. Аналитику и изменение состояния лучше вынести в явный обработчик или watch, если это действительно реакция на изменение.

Безопасный computed
  1. 1Читает реактивные зависимости
  2. 2Синхронно возвращает новое значение
  3. 3Не меняет состояние внутри getter
  4. 4Пересчитывается только при изменении зависимостей
Опасный computed
  1. 1Делает запрос или таймер
  2. 2Мутирует state во время чтения
  3. 3Зависит от обычной внешней переменной
  4. 4Создает устаревший UI или бесконечные обновления

Асинхронная логика и запросы

Computed не подходит для загрузки данных. Запрос имеет состояние: загрузка, ошибка, успешный результат, повтор, отмена, гонка ответов. Если спрятать это в computed, код станет непредсказуемым для UI.

Небезопасный вариант: запускать запрос без отмены и без проверки актуальности. Если пользователь быстро меняет фильтр, старый ответ может прийти позже нового и затереть правильный список. UI покажет данные не для текущего запроса.

Безопаснее следить за фильтром, запускать запрос отдельно, сохранять результат в реактивное состояние и отменять устаревший запрос.

import { ref, watch } from 'vue';

const query = ref('');
const users = ref([]);
const loading = ref(false);
const error = ref(null);

watch(query, async (value, _oldValue, onCleanup) => {
  const controller = new AbortController();

  onCleanup(() => {
    controller.abort();
  });

  loading.value = true;
  error.value = null;

  try {
    const response = await fetch(
      `/api/users?q=${encodeURIComponent(value)}`,
      { signal: controller.signal }
    );

    if (!response.ok) {
      throw new Error('Request failed');
    }

    users.value = await response.json();
  } catch (reason) {
    if (!controller.signal.aborted) {
      error.value = reason;
    }
  } finally {
    if (!controller.signal.aborted) {
      loading.value = false;
    }
  }
});

В реальном коде для быстрых изменений фильтра еще часто добавляют debounce. Но главный тезис для интервью простой: computed не место для async side effects, потому что запросу нужны loading, error, отмена и защита от race condition.

Writable computed

По умолчанию computed только читается. Но во Vue можно описать get и set, чтобы значение можно было записывать. Это часто встречается рядом с v-model или когда нужно проксировать значение из props через emit.

const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`.trim();
  },
  set(value) {
    const [first, ...rest] = value.split(' ');
    firstName.value = first ?? '';
    lastName.value = rest.join(' ');
  },
});

Такой setter допустим, потому что он явно обновляет исходные данные. Но не стоит прятать внутрь setter сетевые запросы, сложный submit или неочевидные побочные эффекты. Иначе обычная запись значения станет слишком дорогой и рискованной.

Практический вывод

На интервью лучше отвечать не только определением, но и правилом выбора. Хорошая короткая формулировка может звучать так:

Computed во Vue это кэшируемое производное значение от реактивного состояния. Я использую его для чистых синхронных расчетов, которые удобно читать в шаблоне. Если нужно выполнить побочный эффект, например запрос или запись во внешнее хранилище, я не кладу это в computed, а использую watch, метод или обработчик события.

После этого можно привести пример с фильтрацией списка. Это покажет, что вы понимаете не только термин, но и практический риск: лишние пересчеты, устаревший UI и side effects при чтении значения.

Частые ошибки

Где обычно ошибаются

Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.

  1. 1

    Путать computed с methods

    Метод выполняется каждый раз, когда вы его вызываете. Если тяжелую фильтрацию списка вызывать из шаблона как метод, можно получить лишнюю работу на каждом рендере. Для производного значения без аргументов лучше вынести логику в computed.
  2. 2

    Делать побочные эффекты в getter

    Getter computed должен только читать данные и возвращать результат. Если внутри менять state, писать в localStorage или отправлять аналитику, чтение значения начнет менять приложение. Это усложняет отладку и может вызвать лишние обновления.
  3. 3

    Класть async-логику в computed

    Computed не предназначен для fetch, await и гонок запросов. Результат запроса храните в реактивном состоянии, а сам запрос запускайте через watch, lifecycle hook или обработчик. Так проще отменять устаревшие запросы, не затирать UI старым ответом, показывать загрузку и обрабатывать ошибки.
  4. 4

    Ожидать реактивности от обычной переменной

    Vue отслеживает зависимости, которые были прочитаны как реактивные. Если computed зависит от обычной переменной вне ref или reactive, изменение этой переменной не приведет к пересчету. В ответе лучше подчеркнуть, что зависимости должны быть частью реактивной системы.
  5. 5

    Использовать computed для всего подряд

    Computed не заменяет методы и обработчики событий. Если функция принимает разные аргументы, выполняет действие или нужна только в одном месте по клику, метод может быть понятнее. На интервью покажите критерий выбора, а не правило "всегда computed".

Follow-up

Что могут спросить дальше

Короткие ответы на вопросы, которыми проверяют понимание computed, реактивности и побочных эффектов во Vue.

Живые ответы

Видео с похожим вопросом

Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.

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

Содержание