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

Есть ли во Vue хук жизненного цикла когда что-либо обновилось?

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

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Хуки жизненного цикла Vue для обновлений

Да, есть несколько хуков. Выбор зависит от того, когда именно нужна реакция на обновление.

Хуки обновления в Vue 3 (Composition API)

1. updated() — после обновления DOM

import { ref, onUpdated } from 'vue';

export default {
  setup() {
    const count = ref(0);
    
    onUpdated(() => {
      console.log('Component updated! DOM refreshed.');
      // Здесь уже можно работать с новым DOM
    });
    
    return { count };
  }
};

Когда срабатывает:

  • После каждого изменения reactive свойства
  • После перерендеринга компонента
  • После обновления DOM
// Пример
const count = ref(0);

onUpdated(() => {
  console.log('Count changed to', count.value); // Выведется много раз!
});

const increment = () => {
  count.value++; // onUpdated сработает
};

2. onBeforeUpdate() — ДО обновления DOM

import { ref, onBeforeUpdate } from 'vue';

export default {
  setup() {
    const count = ref(0);
    
    onBeforeUpdate(() => {
      console.log('About to update. Current count:', count.value);
      // DOM ещё старый!
    });
    
    return { count };
  }
};

Редко используется, но может быть полезно для:

  • Сохранения scroll position
  • Сохранения фокуса элемента
onBeforeUpdate(() => {
  // Сохраняем scroll position перед обновлением
  const scrollPosition = window.scrollY;
  // ...
});

Хуки обновления в Vue 2 (Options API)

То же самое, но синтаксис другой:

export default {
  data() {
    return { count: 0 };
  },
  
  beforeUpdate() {
    console.log('About to update');
  },
  
  updated() {
    console.log('Updated!');
  }
};

Watch — лучший способ реагировать на изменения

Хук updated() срабатывает ДА, но часто watch лучше:

import { ref, watch } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const name = ref('John');
    
    // Реагируем на изменение конкретного свойства
    watch(() => count.value, (newVal, oldVal) => {
      console.log(`Count changed from ${oldVal} to ${newVal}`);
      // Выполняем логику при изменении count
    });
    
    // Реагируем на несколько свойств
    watch([count, name], ([newCount, newName]) => {
      console.log('Count or name changed');
    });
    
    return { count, name };
  }
};

Почему watch лучше updated():

// ПЛОХО — updated() срабатывает на любое изменение
onUpdated(() => {
  if (this.count > 10) {
    alert('Count is too high');
  }
});

// ХОРОШО — watch срабатывает только для count
watch(() => count.value, (newVal) => {
  if (newVal > 10) {
    alert('Count is too high');
  }
});

Практические примеры

1. Сохранение данных при изменении:

const form = ref({ name: '', email: '' });

onUpdated(() => {
  // Сохраняем в localStorage каждый раз (неэффективно)
  localStorage.setItem('form', JSON.stringify(form.value));
});

// ЛУЧШЕ
watch(() => form.value, (newForm) => {
  localStorage.setItem('form', JSON.stringify(newForm));
});

2. Логирование изменений:

const user = ref({ name: '', age: 0 });

onUpdated(() => {
  // Логируем каждое обновление
  console.log('User updated:', user.value);
});

// ЛУЧШЕ
watch(() => user.value, (newUser) => {
  console.log('User changed:', newUser);
}, { deep: true }); // deep: true для вложенных свойств

3. Отправка данных на сервер:

const title = ref('');
const content = ref('');

// Отправляем при каждом изменении любого поля (bad UX)
onUpdated(async () => {
  await fetch('/api/post', {
    method: 'POST',
    body: JSON.stringify({ title: title.value, content: content.value })
  });
});

// ЛУЧШЕ — используем debounce
import { useDebounceFn } from '@vueuse/core';

const savePost = useDebounceFn(async () => {
  await fetch('/api/post', {
    method: 'POST',
    body: JSON.stringify({ title: title.value, content: content.value })
  });
}, 1000);

watch([title, content], savePost);

watchEffect — автоматический watch

Реагирует на все используемые reactive переменные:

import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const multiplier = ref(2);
    
    watchEffect(() => {
      // watchEffect автоматически следит за всеми используемыми переменными
      const result = count.value * multiplier.value;
      console.log(`Result: ${result}`);
      // Срабатывает когда count ИЛИ multiplier меняются
    });
    
    return { count, multiplier };
  }
};

Полный жизненный цикл Vue компонента

import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue';

export default {
  setup() {
    console.log('0. setup() — инициализация');
    
    onBeforeMount(() => {
      console.log('1. onBeforeMount() — ДО монтирования');
    });
    
    onMounted(() => {
      console.log('2. onMounted() — ПОСЛЕ монтирования');
    });
    
    onBeforeUpdate(() => {
      console.log('3. onBeforeUpdate() — ДО обновления');
    });
    
    onUpdated(() => {
      console.log('4. onUpdated() — ПОСЛЕ обновления');
    });
    
    onBeforeUnmount(() => {
      console.log('5. onBeforeUnmount() — ДО удаления');
    });
    
    onUnmounted(() => {
      console.log('6. onUnmounted() — ПОСЛЕ удаления');
    });
    
    return {};
  }
};

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

1. Использование updated() вместо watch:

// ПЛОХО
onUpdated(() => {
  if (this.userData) {
    this.processUserData(); // Срабатывает на каждое обновление!
  }
});

// ХОРОШО
watch(() => userData.value, (newUser) => {
  processUserData();
});

2. Бесконечные циклы:

// ПЛОХО
onUpdated(() => {
  this.count++; // updated() -> count++ -> updated() -> ...
});

// ХОРОШО
watch(() => someOtherValue.value, () => {
  count.value++; // Только реагируем на другое значение
});

3. Забывают про cleanup:

// ПЛОХО — event listener остаётся
onMounted(() => {
  window.addEventListener('resize', handleResize);
});

// ХОРОШО — очищаем при unmount
onMounted(() => {
  window.addEventListener('resize', handleResize);
});

onUnmounted(() => {
  window.removeEventListener('resize', handleResize);
});

Когда я использую каждый хук

onMounted — инициализация (загрузить данные, подписаться) onUpdated — редко, только если нужно что-то сделать ПОСЛЕ обновления DOM watch / watchEffect — основной способ реагировать на изменения onUnmounted — очистка (отписаться, удалить listeners)

Вывод

Да, есть хуки обновления (onUpdated, onBeforeUpdate), но в 95% случаев лучше использовать watch или watchEffect.

Они дают:

  • Больше контроля (можно выбрать что следить)
  • Лучшую производительность (не срабатывает на всё)
  • Понятнее код (явно видно что на что реагирует)