← Назад к вопросам

В чем разница между computed и watch?

2.0 Middle🔥 211 комментариев
#Vue.js

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

В чем разница между computed и watch?

Это вопрос о Vue.js. computed и watch — оба инструмента для реакции на изменения данных, но используются в разных сценариях. Это важные концепции реактивности Vue.

computed — вычисляемые свойства

computed используется для вычисления значения на основе других реактивных данных. Результат кэшируется, пока зависимости не изменятся.

// Vue 3 (Composition API)
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

// Вычисляемое свойство
const fullName = computed(() => {
  console.log('вычисляется...')  // Логирует только при изменении firstName или lastName
  return firstName.value + ' ' + lastName.value
})

console.log(fullName.value)  // "John Doe"
console.log(fullName.value)  // "John Doe" (используется кэшированное значение, перевычисляется не будет)

firstName.value = 'Jane'  // Изменяем зависимость
console.log(fullName.value)  // "Jane Doe" (вычисляется заново)

Свойства computed:

  • Кэширование — результат сохраняется, перевычисляется только при изменении зависимостей
  • Декларативный — описываешь что вычислять, а не как это делать
  • Реактивное — автоматически зависит от других данных
  • Возвращает значение — используется как переменная
  • Синхронное — вычисляется немедленно

Options API вариант:

export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName
    }
  }
}

В шаблоне:

<template>
  <div>
    <p>{{ fullName }}</p>  <!-- "John Doe" -->
  </div>
</template>

watch — наблюдатели

watch используется для выполнения побочных эффектов (side effects) в ответ на изменение данных. Это функция, которая запускается при изменении.

// Vue 3 (Composition API)
import { ref, watch } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')
const fullName = ref('')

// Наблюдатель
watch(
  firstName,  // Что наблюдаем
  (newValue, oldValue) => {  // Что делаем при изменении
    console.log(`Имя изменилось с ${oldValue} на ${newValue}`)
    fullName.value = newValue + ' ' + lastName.value
  }
)

firstName.value = 'Jane'  // Логирует: "Имя изменилось с John на Jane"

Свойства watch:

  • Побочные эффекты — выполняет код, имеющий сторонние эффекты
  • Императивный — описываешь что именно делать при изменении
  • Доступ к старому значению — можешь сравнить старое и новое
  • Асинхронный — может содержать async код
  • НЕ возвращает значение — просто выполняет действие

Options API вариант:

export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe',
      fullName: ''
    }
  },
  watch: {
    firstName(newValue, oldValue) {
      console.log(`Имя изменилось с ${oldValue} на ${newValue}`)
      this.fullName = newValue + ' ' + this.lastName
    }
  }
}

Сравнение: computed vs watch

Критерийcomputedwatch
НазначениеВычисление значенияПобочные эффекты
КэшированиеДа, пока зависимости не изменятсяНет
СинхронностьСинхронноеАсинхронное допускается
Возврат значенияДа, возвращает значениеНет, просто выполняет код
ПроизводительностьВыше (кэш)Ниже (запускается всегда)
Параметры колбэка(oldValue, newValue)(newValue, oldValue)
Множественные зависимостиДаНужен массив

Примеры использования

1. computed — ТА БУДЕ ИСПОЛЬЗОВАТЬ в 80% случаев

Этот вариант лучше:

const firstName = ref('John')
const lastName = ref('Doe')

// ✅ Правильно — используем computed
const fullName = computed(() => firstName.value + ' ' + lastName.value)

template: '<p>{{ fullName }}</p>'  // Просто используем как переменная

Плюсы:

  • Кэширование (быстрее)
  • Проще (описываешь что вычислять)
  • Реактивно в шаблонах

2. watch — для побочных эффектов

Этот случай требует watch:

const searchQuery = ref('')
const results = ref([])
const isLoading = ref(false)

// ✅ Правильно — используем watch для API запроса
watch(
  searchQuery,
  async (newQuery) => {
    if (!newQuery) {
      results.value = []
      return
    }
    
    isLoading.value = true
    try {
      const response = await fetch(`/api/search?q=${newQuery}`)
      results.value = await response.json()
    } catch (error) {
      console.error('Ошибка поиска:', error)
    } finally {
      isLoading.value = false
    }
  },
  { debounce: 300 }  // Опция для debounce
)

Почему watch: Нужно выполнить асинхронный API запрос — это побочный эффект.

3. watch с глубокими объектами

const user = ref({ name: 'John', age: 30 })

// watch не видит изменения внутри объекта
watch(user, () => {
  console.log('пользователь изменился')
})

user.value.name = 'Jane'  // НЕ запустит watch

// Нужна опция deep: true
watch(
  user,
  () => {
    console.log('пользователь изменился')
  },
  { deep: true }  // Следить за вложенными изменениями
)

user.value.name = 'Jane'  // Теперь запустит watch

4. Наблюдение за несколькими свойствами

watch(
  [firstName, lastName],  // Массив зависимостей
  ([newFirst, newLast], [oldFirst, oldLast]) => {
    console.log(`Изменилось: ${oldFirst}/${oldLast} -> ${newFirst}/${newLast}`)
  }
)

Опции watch

watch(
  searchQuery,
  async (newQuery) => { /* ... */ },
  {
    immediate: true,      // Запустить сразу при создании
    deep: true,           // Следить за вложенными изменениями
    flush: 'post',        // Запустить после обновления DOM
    debounce: 300,        // Ждать 300ms после последнего изменения
  }
)

Когда использовать что?

Используй computed для:

  • Вычисления производных значений (fullName, filterList, count)
  • Форматирования данных (дата, валюта, текст)
  • Логических выражений (isAdmin, isVisible)
  • Когда результат должен быть в реактивной переменной

Используй watch для:

  • API запросов
  • Логирования
  • Изменения несвязанных данных
  • Интеграции с внешними библиотеками
  • Побочных эффектов

Anti-pattern: не делай так

// ❌ ПЛОХО — используешь watch вместо computed
const fullName = ref('')
watch([firstName, lastName], ([first, last]) => {
  fullName.value = first + ' ' + last
})

// ✅ ХОРОШО — используешь computed
const fullName = computed(() => firstName.value + ' ' + lastName.value)
// ❌ ПЛОХО — используешь computed для побочных эффектов
const results = computed(async () => {
  return await fetch(...).then(r => r.json())
})

// ✅ ХОРОШО — используешь watch
watch(searchQuery, async (query) => {
  results.value = await fetch(...).then(r => r.json())
})

Вывод

  • computed — для вычисления значений (детерминированные, кэшируемые)
  • watch — для реакции на изменения (побочные эффекты)

В 80% случаев используешь computed, в 20% — watch. Если не уверен — начни с computed, потом перейди на watch если нужны побочные эффекты.