Елена Захарова
Понимание жизненного цикла компонента Vue js на примере mounted
Введение
Жизненный цикл компонента — это последовательность этапов, через которые проходит каждый компонент Vue.js от создания до удаления со страницы. Хорошее понимание жизненного цикла — одна из базовых вещей для эффективной работы с Vue. Если вы знаете, когда и в каком порядке происходят события, становится намного проще управлять логикой и состоянием ваших компонентов. В этой статье я подробнее расскажу о жизненном цикле на примере одного из самых используемых хуков — mounted
. На реальных примерах вы увидите, почему важно знать, как и когда выполнять определённые действия.
Жизненный цикл компонента Vue.js
Общее представление о жизненном цикле
Давайте разберём, что вообще происходит с компонентом Vue, начиная с его появления и вплоть до уничтожения. Вот основные этапы жизненного цикла:
- Инициализация. Vue создает экземпляр компонента, устанавливает реактивные свойства из
data
, вычисляемые значения и методы. - Монтаж (mounting). Компонент "прикрепляется" к DOM, становится видимым на странице.
- Обновление. Каждый раз, когда изменяются реактивные данные, компонент реагирует обновлением отображения.
- Разрушение (unmounting). Компонент удаляется из DOM, и происходит очистка ресурсов.
На каждом из этих этапов срабатывают специальные хуки — "жизненные события". Это функции, которые вы можете определить внутри компонента, чтобы выполнять нужную логику.
Какие жизненные хуки существуют
Основные жизненные хуки в компонентах Vue:
beforeCreate
— вызывается перед инициализацией данных и событий.created
— вызывается непосредственно после инициализации данных.beforeMount
— перед тем, как компонент будет смонтирован.mounted
— сразу после монтирования в DOM (тема нашей статьи).beforeUpdate
— перед тем, как компонент будет обновлён.updated
— после обновления DOM из-за реактивных изменений.beforeUnmount
(Vue 3) илиbeforeDestroy
(Vue 2) — перед удалением компонента.unmounted
(Vue 3) илиdestroyed
(Vue 2) — после удаления элемента и очистки.
Этот набор хуков покрывает все основные события жизненного цикла. Каждый из них решает свои задачи, а сейчас давайте подробнее остановимся на mounted
.
Хук mounted: зачем он нужен и когда срабатывает
В чем суть mounted
mounted
— это хук жизненного цикла, который вызывается после того, как Vue отрисовал компонент и вставил его в DOM-дерево. Это очень важный момент: если в created
элемент в DOM ещё не появился, то в mounted
уже можно быть уверенным, что он на странице. Поэтому все действия, которые требуют доступа к реальному DOM (например, работа с библиотеками, которые манипулируют DOM напрямую, или измерение размеров элементов), выполняются именно в этом хуке.
Когда нужно использовать mounted
Здесь некоторые типичные задачи для mounted
:
- Инициализация сторонних библиотек, зависящих от DOM.
- Получение размеров или положения элементов.
- Установка обработчиков событий на элементы, которых нет в шаблоне Vue.
- Первый запуск асинхронных операций, если они зависят от DOM.
Обратите внимание: хотя вы часто будете запускать асинхронный код (например, загрузку данных) в mounted
, это не всегда необходимо делать именно здесь. Иногда лучше загружать данные ещё раньше — например, в хуке created
.
Простой пример использования mounted
Вот как можно определить и использовать хук mounted
в компоненте:
export default {
name: 'ExampleComponent',
mounted() {
// Здесь можно получить доступ к элементам через this.$refs или напрямую к DOM
console.log('Компонент смонтирован и появился в DOM');
// Например, измерить элемент по ref
const height = this.$refs.myBlock.offsetHeight;
console.log('Высота элемента:', height);
},
template: `
<div ref="myBlock">
Я пример блока для измерения
</div>
`
}
В этом примере мы выводим в консоль сообщение, а также измеряем высоту DOM-элемента после монтирования. Вам не нужно переживать — в этот момент элемент точно уже существует в DOM.
Взаимодействие с DOM и сторонними библиотеками
Частая задача — интеграция библиотек типа jQuery, Chart.js, Leaflet. Если такие библиотеки работают с DOM напрямую, их нельзя запускать до хука mounted
: элемент просто не будет найден.
Смотрите, как это реализуется на практике:
import Chart from 'chart.js/auto';
export default {
mounted() {
// Здесь this.$refs.chartCanvas гарантированно есть в DOM
this.chart = new Chart(this.$refs.chartCanvas, {
type: 'bar',
data: {...},
options: {...}
});
},
beforeUnmount() {
// Важно чистить за собой ресурсы!
if (this.chart) {
this.chart.destroy();
}
},
template: '<canvas ref="chartCanvas"></canvas>'
}
В этом коде мы создаем график, после того как элемент canvas появился на странице. И дополнительно проводим очистку в хуке beforeUnmount
, чтобы не было утечек памяти.
Асинхронные операции в mounted
Асинхронные задачи вроде загрузки данных часто встречаются в этом хуке. Например, получение данных с сервера:
export default {
data() {
return {
users: []
}
},
async mounted() {
// Здесь мы можем обращаться к fetch или axios
const response = await fetch('https://jsonplaceholder.typicode.com/users');
this.users = await response.json();
},
template: `
<ul>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
`
}
Такой подход удобен, когда вам нужно показать какие-то данные сразу после появления компонента.
Однако, если компоненту не нужен DOM для загрузки данных, такое же действие можно сделать в хуке created
— он сработает раньше, что может быть полезно для плавности UI.
Почему не стоит манипулировать DOM до mounted
Обратите внимание: если попытаться обратиться к DOM в хуках вроде created
или даже beforeMount
, там ещё просто не будет нужных элементов. Покажу вам простую демонстрацию:
export default {
created() {
// На этом этапе элементы ещё не существуют, вернется undefined
console.log(this.$refs.someElement); // undefined
},
mounted() {
// Здесь уже есть доступ к элементу
console.log(this.$refs.someElement); // DOM-элемент
},
template: '<div ref="someElement"></div>'
}
Именно поэтому такие действия возможны только после появления компонента на странице.
Последовательность хуков жизненного цикла (демонстрация)
Чтобы наглядно понять порядок срабатывания хуков, посмотрите, как они выведутся в консоль:
export default {
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
mounted() {
console.log('mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
beforeUnmount() {
console.log('beforeUnmount');
},
unmounted() {
console.log('unmounted');
},
template: `
<div>Пример компонента</div>
`
}
Если вы используете Vue 2, вместо beforeUnmount
и unmounted
будут beforeDestroy
и destroyed
. Но логика работы одинаковая.
Как обращаться к элементам через $refs
Основной способ работать с DOM-элементами — это ссылка через ref
. Покажу стандартный прием:
export default {
mounted() {
// После монтирования $refs.input доступен
this.$refs.input.focus(); // Установим фокус в поле ввода
},
template: '<input ref="input" />'
}
Это полезно для сценариев вроде автозаполнения или инициализации фокуса.
Можно ли передавать параметры в mounted?
Нет, в отличие от обычных методов, жизненные хуки всегда вызываются Vue без параметров. Если вам нужно получить какие-то данные, делайте это через свойства компонента (props
), data
, или вычисляемые свойства (computed
).
Когда mounted НЕ вызывается
Бывают случаи, когда вы ожидаете срабатывания mounted
, но хук не вызывается:
- Если компонент не был добавлен в шаблон или динамически не был смонтирован.
- Если компонент отрисован с условием (
v-if="false"
), пока условие не стало истинным. - Если компонент был удалён до момента завершения монтирования.
Проверьте, что компонент реально появляется в DOM, иначе чудес не произойдёт.
Использование mounted во Vue 3 и Vue 2
Синтаксис практически не отличается. Главное отличие связано с переходом к Composition API, но сам хук работает одинаково.
Вот пример с Composition API (Vue 3):
import { onMounted, ref } from 'vue';
export default {
setup() {
const input = ref(null);
onMounted(() => {
// input.value — это DOM-элемент
input.value.focus();
});
return { input };
},
template: '<input ref="input" />'
}
onMounted
— это аналог стандартного хука, но работает внутри функции setup.
Как правильно управлять ресурсами: очистка и отписка в паре с mounted
Важно помнить: если вы что-то "инициализировали" в mounted, часто требуется делать обратную операцию в хуке "разрушения" (beforeUnmount
или destroyed
). Это избавит от утечек памяти.
Пример очистки после медиа-запроса:
export default {
mounted() {
// Подключаем обработчик события на window
window.addEventListener('resize', this.handleResize);
},
beforeUnmount() {
// Снимаем обработчик перед удалением компонента
window.removeEventListener('resize', this.handleResize);
},
methods: {
handleResize() {
console.log('Изменён размер окна');
}
},
template: '<div>Следим за размером окна</div>'
}
Всегда возвращайтесь к этому вопросу, если используете setInterval, сторонние DOM-библиотеки, обработчики событий вне Vue — всем им нужна последующая ручная очистка.
Заключение
Хук mounted
— один из самых востребованных жизненных хуков в компонентах Vue.js. Он позволяет быть уверенным, что DOM уже существует и можно спокойно выполнять любые действия, связанные с визуализацией, интеграцией внешних библиотек, обработкой событий и измерением элементов страницы. Работа с этим хуком, а также с парными хуками удаления компонентов, лежит в основе грамотного управления жизненным циклом. Регулярное использование mounted
делает вашу архитектуру надёжнее, безопаснее и даже улучшает производительность, если вы всё делаете по уму.
Частозадаваемые технические вопросы по теме статьи и ответы на них
Как заставить компонент "дождаться" mounted для выполнения асинхронного запроса?
Вам не нужно "ждать" mounted вручную — просто поместите асинхронный запрос внутрь mounted:
mounted() {
this.loadDataAsync();
},
methods: {
async loadDataAsync() {
// ваш запрос тут
}
}
Vue вызовет mounted тогда, когда компонент будет смонтирован.
Почему $refs иногда равен undefined в mounted?
Если вы используете условный рендеринг (v-if
), элемент может появиться в DOM не сразу. Проверьте, что переменная, от которой зависит v-if, истинна к моменту выполнения mounted, или используйте nextTick
:
mounted() {
this.$nextTick(() => {
// здесь $refs будет точно определён
console.log(this.$refs.input);
});
}
Можно ли использовать setTimeout в mounted для задержек?
Да, можно. Основное — очищайте таймеры в хуке beforeUnmount:
mounted() {
this.timerId = setTimeout(() => { ... }, 1000);
},
beforeUnmount() {
clearTimeout(this.timerId);
}
Как отследить, что дочерний компонент тоже смонтирован?
Добавьте $refs на дочерний компонент и используйте его $el в $nextTick, или ловите кастомные события, которые эмитятся дочерним компонентом из его mounted:
// В дочернем компоненте
mounted() {
this.$emit('mounted');
}
Можно ли перезапустить mounted повторно без перерендера всего компонента?
Нет. Хук mounted стандартно вызывается только один раз при монтировании. Если вам нужно повторить некую логику, вынесите её в отдельный метод и вызывайте вручную.