Друзья, привет!

Практическое понимание событий жизненного цикла компонентов даёт возможность быстро анализировать и разрабатывать бизнес-задачи. Мы разберём 7 событий жизненного цикла компонентов на примере Composition API в Vue3 фреймворке.

onBeforeMount()

Событие жизненного цикла срабатывает до появления компонента в DOM дереве.

  • Первым из всех событий жизненного цикла имеет доступ к реактивным данным.

  • Компонент создан. Первая фаза рендеринга не началась. Компонента ещё нет в DOM дереве.

Сигнатура метода

onBeforeMount(callback(): void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

Пример: получение данных с сервера

Мы можем запросить данные с сервера сразу после настройки реактивного состояния компонента в <script setup>. Компонент ещё не виден пользователю, но необходимые данные с сервера уже запрошены.

// <script setup>
import {onBeforeMount, ref} from "vue";

const users = ref<{id: number, name: string}[]>([]);

onBeforeMount(async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  users.value = await response.json()
})
// template
<ul>
  <li v-for="user of users">{{user.name}}</li>
</ul>

Пример: регистрация событий DOM

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

// <script setup>
import {onBeforeMount} from "vue";
const width = ref(window.innerWidth)

const reszie = () => {
  width.value = window.innerWidth;
}

onBeforeMount(() => {
  window.addEventListener('resize', resize);
})

onMounted()

Событие жизненного цикла срабатывает после появления компонента в DOM дереве.

  • Компонент считается смонтированным, если все дочерние синхронные компоненты смонтированы.

  • Компонент отображается в DOM дереве.

Сигнатура метода

onMounted(callback: () => void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

Пример: инициализация сторонней библиотеки

Для примера возьмем библиотеку отображения графиков Chart.js. Данная библиотека требует на вход ссылку на DOM элемент. Хук onMounted срабатвыает после отображения шаблона компонента в DOM дереве. Реактивная ссылка chartRef будет иметь указатель на canvas элемент.

// <script setup>
import {onMounted, ref} from "vue";
const canvasRef = ref<HTMLCanvasElement | null>(null)
const chartRef = shallowRef<ChartJS | null>(null)


onMounted(() => {
  chartRef.value = new ChartJS(canvasRef.value, config as any)
})
// template
<canvas ref="canvasRef"/>

Пример: получение данных из внешнего источника

Если после отображения компонента нам необходимы дополнительные данные с сервера, то используем onMounted() событие.

// <script setup>
import {onMounted, ref} from "vue";

const users = ref<{id: number, name: string}[]>([]);

onMounted(async () => {
  const response = await fetch("http://localhost:3000/users");
  users.value = await response.json()
})
// template
<ul>
  <li v-for="user of users">{{user.name}}</li>
</ul>

Пример: регистрация событий DOM

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

// <script setup>
import {onMounted, ref} from "vue";
const width = ref(window.innerWidth)

const reszie = () => {
  width.value = window.innerWidth;
}

onMounted(() => {
  window.addEventListener('resize', resize)
})

onBeforeUpdate()

Срабатывае до обновления DOM дерева. Используется для взаимодействия с DOM деревом. Безопасно изменять состояние компонента.

Сигнатура метода

onBeforeUpdate(callback: () => void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

Пример: удаление ссылок на компоненты

Если нам необходимо хранить массив ссылок на элементы шаблона нашего компнента, то при изменении кол-ва элементов, необходимо обновить реактивные данные. Если мы используе ref с v-for в шаблоне компонента, то нет гарании, что массив ref будет хранить туже последовательность, что и данные в v-for. Нам нужно самим управлять массивом HTML элементов.

// <script setup>
import {onBeforeUpdate, shallowRef} from "vue";
const liElements = shallowRef<(HTMLLIElement | undefined) []>([])

onBeforeUpdate(() => {
  liElements.value = []
})

const onUpdateRef = (e: any, index: number) => {
  liElements.value[index] = e
}
// template
<li v-for="(user, index) in users"
          :ref="e => onUpdateRef(e, index)"
          :key="user.id"
          tabindex="1"
          @click="onItemClick(user.id)">{{user.name}}</li>

onUpdated()

Callback функция срабатывает после изменения DOM дерева компонентов в соответствии с реактивным сотоянием компонента. Различные изменения состояния объединяются в один цикл рендеринга компонента для отпимизации производительности.

Сигнатура метода

onMounted(callback: () => void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

Пример: получение применённого реактивного стостояния в DOM дереве.

Пользователь нажимает на кнопку, реактивное состояние компонента изменяется и применяется к DOM. Callback в onUpdated методе содержит одинаковые данные как в DOM, так и в реактивном состоянии.

// <script setup>
import {onUpdated, ref} from "vue";

const count = ref(0)
const divRef = ref<HTMLDivElement | null>(null)

onUpdated(() => {
  const divCountValue = parseInt(divRef.value.innerHTML)
  // divCountValue === count => true
  console.log(divCountValue === count.value)
})
// template
  <div ref="divRef">{{count}}</div>
  <button @click="count++">Count</button>

onBeforeUnmounted()

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

Сигнатура метода

onBeforeUnmounted(callback: () => void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

Пример: удаление таймеров созданных в компоненте

Регистрация событий, таймеров происходит в onBeforeMount или onMounted в зависимости от целей задачи. Очистка зарегестрированных обработчиков выполняется в onBeforeUnmount.

// <script setup>
let intervalId;

onMounted(() => {
  intervalId = setInterval(() => {
    // logic here
  },1000)
})

onBeforeUnmount(() => {
  clearInterval(intervalId)
})

onUnmounted()

Компонент уничтожен. Все реактивные состояния остановлены. Мы можем взаимодействовать с созданными подписками таймеров, DOM или подключением к серверу.

Сигнатура метода

onUnmounted(callback: () => void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

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

Удаление обработчика события изменения окна.

// <script setup>
import {onMounted, onUnmounted, ref} from "vue";
const size = ref({width: window.innerWidth, height: window.innerHeight})

const resize = () => {
  size.value.width = window.innerWidth
  size.value.height = window.innerHeight
}

onMounted(() => {
  window.addEventListener('resize', resize)
})

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

onErrorCaptured()

Метод предоставляет возможность перехватывать ошибки в компоненте. Ошибки кода в <script setup>, рендеринга, обработчиков событий, функций жизненного цикла компонента, наблюдателей, директив и переходов.

Сигнатура метода

onBeforeUnmounted(callback: () => void): void

Выполнение функции callback синхронное. Можно выполнять асинхронный код в callback функции. Vue фреймворк не будет ждать завершение исполнения асинхронного кода.

Пример: отображение ошибки из дочернего компонента

Важно отображать ошибку без влияния на состояние компонента, которое привело к ошибки, иначе будет бесконечный цикл.

// <script setup>
const error = ref<string | undefined>()

onErrorCaptured((err, instance, info) =>{
  error.value = err.message;
})
// template
  <ErrorComponent v-if="!error"/>
  <div v-if="error">Error: {{error}}</div>

Резюме

Понимание событий жизненного цикла компонента упрощает реализацию бизнес-задач.

Lifecycle Hook

Когда

Для чего

onBeforeMount

до вставки в DOM

регистрация глобального событи, получение данных из внешнего источника

onMounted

после вставки в DOM

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

onBeforeUpdate

до обновления DOM

получить состояние DOM до обновления

onUpdated

после обновления DOM

получить обновлённое состояние DOM

onBeforeUnmount

до уничтожения компонента

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

onUnmounted

компонент уничтожен

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

onErrorCaptured

во время возникновения ошибки на этапе жизни компонента

поймать ошибки компонента

Ссылка на исходный код.

Статья подготовлена в преддверии старта курса Vue.js Developer. Узнать подробнее о курсе.

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


  1. gmtd
    19.04.2024 09:50
    +2

    Без setup() картина неполная


    1. danilovmy
      19.04.2024 09:50

      <zanuda mode="on">

      В setup() компонента, как такового (тот самый this), еще не существует. Потому setup() не является событием жизни компонента. А статья именно про жизненный цикл, так что - все норм.

      </zanuda>


      1. gmtd
        19.04.2024 09:50


        1. danilovmy
          19.04.2024 09:50

          Да, спасибо. Стоило бы все же указать источник. Так вот, эта диаграмма подтверждает то, что компонента на этапе функции setup() не существует. В диаграмме даже отмечено цветом то, что функция Setup() (синий) не входит в список Component Lifecycle Hooks (красный), о которых рассказывается в текущей статье.


          1. gmtd
            19.04.2024 09:50

            Если во время setup ничего нет, то куда же цепляются переменные, которые в нем объявляются?


            1. danilovmy
              19.04.2024 09:50

              Цитируя документацию, ссылку на которую я привел в первом ответе:

              setup() не имеет доступа к компоненту экземпляра — thisбудет иметь значение undefinedвнутри setup()

              Инициализация объекта происходит непосредственно перед вызовом beforeCreate (Called immediately when the instance is initialized and props are resolved)

              Это действительно может смущать, что есть какие-то переменные, которые объявляются до появления instance, и они станут атрибутами this после. Мы даже можем управлять видимостью этих переменных и решать, какие переменные в setup(), будут после отображены в instance, как атрибуты или методы. Ещё setup() может вернуть объекты явно, и такие объекты станут сразу отображены в глобальной зоне видимости всех элементов компонента, аналогично props-ам.


  1. functyon
    19.04.2024 09:50

    стоило добавить activated, deactivated и, может быть, остальные из документации