Жизненный цикл веб-компонентов

Жизненный цикл веб-компонента описывает последовательность этапов, через которые проходит компонент от создания до удаления из DOM. Понимание этих этапов критично для эффективного управления состоянием, оптимизации рендеринга и взаимодействия с внешними данными.


1. Создание компонента

Когда создаётся новый экземпляр компонента, сначала вызывается конструктор класса:

import { LitElement, html, css } from 'lit';

class MyElement extends LitElement {
  constructor() {
    super();
    this.title = 'Пример';
  }
}
customElements.define('my-element', MyElement);

Ключевые моменты:

  • В конструкторе следует инициализировать внутренние свойства, но не манипулировать DOM, так как элемент ещё не присоединён к дереву документа.
  • Для реактивных свойств используется объявление через статическое свойство properties.
static properties = {
  title: { type: String }
};

2. Подключение к DOM (connectedCallback)

Метод connectedCallback вызывается, когда элемент добавлен в DOM:

connectedCallback() {
  super.connectedCallback();
  console.log('Компонент подключен к DOM');
}

Особенности:

  • Можно выполнять подписки на события или инициализацию сторонних библиотек.
  • Этот метод вызывается каждый раз, когда элемент добавляется в DOM, даже если он был удалён и добавлен повторно.

3. Обновление свойств и рендеринг (update и render)

Lit использует реактивную модель обновления. При изменении реактивного свойства автоматически запускается процесс обновления:

updated(changedProperties) {
  if (changedProperties.has('title')) {
    console.log(`title изменён с ${changedProperties.get('title')} на ${this.title}`);
  }
}

render() {
  return html`<h1>${this.title}</h1>`;
}

Важные аспекты:

  • render вызывается каждый раз, когда одно из реактивных свойств изменяется.
  • update — промежуточный этап, где можно контролировать, будет ли выполнен рендер.
  • Использование shouldUpdate(changedProperties) позволяет оптимизировать рендеринг:
shouldUpdate(changedProperties) {
  return changedProperties.has('title');
}

4. Отключение от DOM (disconnectedCallback)

Метод disconnectedCallback вызывается при удалении элемента из DOM:

disconnectedCallback() {
  super.disconnectedCallback();
  console.log('Компонент удалён из DOM');
}

Назначение:

  • Освобождение ресурсов, отмена подписок на события, остановка таймеров.
  • Предотвращение утечек памяти при динамическом создании и удалении компонентов.

5. Обработка атрибутов (attributeChangedCallback)

Lit автоматически связывает реактивные свойства с атрибутами HTML. При изменении атрибута вызывается:

attributeChangedCallback(name, oldValue, newValue) {
  super.attributeChangedCallback(name, oldValue, newValue);
  console.log(`Атрибут ${name} изменён с ${oldValue} на ${newValue}`);
}

Особенности:

  • Поддерживается конвертация типов (String, Number, Boolean, Object) через декларацию свойств.
  • Изменения через JavaScript и через HTML синхронизируются автоматически.

6. Стилизация и Shadow DOM

Lit по умолчанию использует Shadow DOM, изолируя стили компонента:

static styles = css`
  h1 {
    color: blue;
  }
`;

Значение в жизненном цикле:

  • Стили применяются при первом рендере.
  • Shadow DOM защищает внутренние элементы от внешних стилей, что предотвращает конфликт CSS при динамическом обновлении.

7. Асимметричные сценарии обновления

Иногда требуется асинхронное обновление данных перед рендером. Для этого используют requestUpdate:

async firstUpdated() {
  const data = await fetchData();
  this.data = data;
  this.requestUpdate();
}

Пояснение:

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

8. События жизненного цикла

Lit позволяет внедрять дополнительные кастомные события на разных этапах:

this.dispatchEvent(new CustomEvent('ready', { detail: { time: Date.now() } }));

Рекомендации:

  • Использовать события для интеграции компонента с внешними приложениями.
  • Обеспечивать возможность подписки на ключевые этапы: загрузка, обновление, удаление.

Жизненный цикл Lit сочетает в себе возможности стандартных веб-компонентов с реактивной моделью рендеринга. Глубокое понимание последовательности методов позволяет создавать эффективные, устойчивые к изменениям DOM компоненты, минимизировать повторный рендер и управлять ресурсами на протяжении всего времени существования элемента.