Реактивность в Vue 3: watch, watchEffect и продвинутые техники

Vue 3 представляет мощную систему реактивности, которая является фундаментом для создания современных веб-приложений. В этом руководстве мы глубоко погрузимся в механизмы отслеживания изменений, рассмотрим все аспекты работы watch и watchEffect, а также изучим продвинутые паттерны работы с реактивностью.

Основы реактивности в Vue 3

Vue 3 полностью переработал систему реактивности, используя JavaScript Proxy вместо Object.defineProperty. Это обеспечивает:

  • Поддержку работы с массивами и коллекциями
  • Более эффективное отслеживание изменений
  • Возможность создания «сырых» (raw) объектов без реактивности
  • Лучшую интеграцию с TypeScript

Как работает реактивность

import { reactive, effect } from 'vue'

const state = reactive({
  count: 0
})

// Аналог watchEffect в системе реактивности
effect(() => {
  console.log('Count:', state.count)
})

watch vs watchEffect: полное сравнение

watchEffect

  • Автоматическое отслеживание зависимостей
  • Немедленный запуск при создании
  • Не предоставляет старые значения
  • Идеален для побочных эффектов
const count = ref(0)

watchEffect(() => {
  console.log(`Count changed: ${count.value}`)
})

watch

  • Явное указание источников
  • Ленивое выполнение (по умолчанию)
  • Предоставляет старые и новые значения
  • Подходит для сравнения состояний
watch(count, (newVal, oldVal) => {
  console.log(`Count changed from ${oldVal} to ${newVal}`)
})

Продвинутые техники работы с реактивностью

1. Контроль зависимостей

const condition = ref(false)
const a = ref(1)
const b = ref(2)

watchEffect(() => {
  // Только condition будет зависимостью
  if (condition.value) {
    console.log(a.value + b.value) // a и b не станут зависимостями
  }
})

2. Глубокое наблюдение с кастомным сравнением

watch(
  () => ({ ...complexObject }),
  (newVal, oldVal) => {
    // Логика сравнения
  },
  {
    deep: true,
    equals: (a, b) => 
      a.id === b.id && a.items.length === b.items.length
  }
)

3. Реактивные цепочки и оптимизация

const searchQuery = ref('')
const filters = reactive({ 
  category: '', 
  sort: 'asc',
  // 10K элементов
  items: hugeArray 
})

// Оптимизированный watch
watch(
  () => ({
    query: searchQuery.value,
    category: filters.category,
    sort: filters.sort
  }),
  ({ query, category, sort }) => {
    // Фильтрация без отслеживания hugeArray
    filterItems(query, category, sort)
  }
)

Практические примеры из реальных проектов

1. Интеграция с API

const pagination = reactive({
  page: 1,
  size: 20,
  total: 0
})

const fetchData = async () => {
  const res = await api.get('/items', {
    params: {
      page: pagination.page,
      size: pagination.size
    }
  })
  pagination.total = res.total
}

// Автоматический запрос при изменении пагинации
watch([() => pagination.page, () => pagination.size], fetchData, {
  immediate: true
})

2. Управление состоянием формы

const form = reactive({
  email: '',
  password: '',
  errors: {}
})

watch(
  () => form.email,
  (email) => {
    form.errors.email = validateEmail(email) 
      ? null 
      : 'Invalid email format'
  },
  { debounce: 300 }
)

Производительность и отладка

1. Измерение времени выполнения

watchEffect((onCleanup) => {
  const start = performance.now();
  
  // Тяжелая операция
  processLargeData();
  
  const duration = performance.now() - start;
  if (duration > 50) {
    console.warn(`Slow effect: ${duration.toFixed(2)}ms`);
  }
  
  onCleanup(() => {
    // Очистка ресурсов
  })
})

2. Визуализация зависимостей

function trackDependencies(effect) {
  const deps = new Set()
  
  const reactiveEffect = watchEffect(() => {
    effect()
    console.log('Dependencies:', [...deps])
    deps.clear()
  }, {
    onTrack(e) {
      deps.add(e.target[e.key])
    }
  })
  
  return reactiveEffect
}

Заключение и лучшие практики

  • Используйте watch когда нужны старые значения или точный контроль
  • Выбирайте watchEffect для автоматического отслеживания зависимостей
  • Оптимизируйте глубокое наблюдение с помощью кастомных функций сравнения
  • Разделяйте сложные эффекты на несколько простых watchers
  • Всегда очищайте ресурсы в onCleanup
  • Мониторьте производительность сложных эффектов

Эти техники помогут вам создавать высокопроизводительные приложения с четкой и предсказуемой реактивностью.

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *