Управление состоянием компонентов

В Lit состояние компонентов является центральным элементом их реактивности. Под состоянием понимаются данные, которые определяют, как компонент отображается, и изменение которых автоматически инициирует повторный рендеринг шаблона. Управление состоянием в Lit осуществляется через свойства класса, декораторы и специальные методы жизненного цикла.

Реактивные свойства

Реактивное свойство — это свойство класса компонента, за изменением которого следит Lit. Оно объявляется с помощью декоратора @property:

import { LitElement, html, css } from 'lit';
import { property } from 'lit/decorators.js';

class CounterComponent extends LitElement {
  @property({ type: Number })
  count = 0;

  render() {
    return html`
      <div>Счётчик: ${this.count}</div>
      <button @click=${() => this.count++}>Увеличить</button>
    `;
  }
}
customElements.define('counter-component', CounterComponent);

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

  • Декоратор @property делает свойство реактивным.
  • Любое изменение count автоматически вызывает render.
  • Можно указывать тип свойства через { type: Number | String | Boolean | Array | Object }.

Локальное состояние через state

Для внутреннего состояния, которое не должно быть публичным API компонента, используется декоратор @state:

import { state } from 'lit/decorators.js';

class ToggleComponent extends LitElement {
  @state()
  private _toggled = false;

  render() {
    return html`
      <button @click=${this._toggle}>${this._toggled ? 'Включено' : 'Выключено'}</button>
    `;
  }

  _toggle() {
    this._toggled = !this._toggled;
  }
}
customElements.define('toggle-component', ToggleComponent);

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

  • Состояние приватное и не отражается в атрибутах HTML.
  • Используется для внутренних механик компонента.
  • Не вызывает нежелательную сериализацию данных в DOM.

Свойства и атрибуты

Состояние компонента может синхронизироваться с атрибутами HTML. Свойство можно связать с атрибутом через reflect: true:

@property({ type: Boolean, reflect: true })
active = false;

Эффекты:

  • Любое изменение свойства обновляет соответствующий атрибут.
  • Изменение атрибута снаружи обновляет свойство.
  • Полезно для CSS-селекторов и взаимодействия с другими библиотеками.

Методы жизненного цикла и управление состоянием

Lit предоставляет несколько методов жизненного цикла, позволяющих контролировать состояние:

  • connectedCallback() — вызывается при добавлении элемента в DOM. Можно инициализировать состояние или запускать подписки.
  • disconnectedCallback() — очистка ресурсов, отписка от событий.
  • updated(changedProperties) — вызывается после обновления состояния. Можно реагировать на конкретные изменения:
updated(changedProperties) {
  if (changedProperties.has('count')) {
    console.log(`Новое значение count: ${this.count}`);
  }
}
  • willUpdate(changedProperties) — вызывается до рендеринга, позволяет скорректировать состояние.

Реактивные массивы и объекты

Для массивов и объектов важно создавать новые ссылки, чтобы Lit заметил изменения:

this.items = [...this.items, newItem];
this.config = { ...this.config, option: true };

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

Связывание с событиями

Часто состояние изменяется через события пользователя. В Lit используется синтаксис @event:

<button @click=${this._increment}>Добавить</button>

Метод _increment изменяет реактивное свойство, что автоматически инициирует рендеринг.

Оптимизация рендеринга

Lit применяет шаблонное дифференцирование, обновляя только изменённые части DOM. Для больших состояний и массивов можно использовать repeat:

import { repeat } from 'lit/directives/repeat.js';

html`
  <ul>
    ${repeat(this.items, item => item.id, item => html`<li>${item.name}</li>`)}
  </ul>
`;

Это позволяет эффективно обновлять списки без полной перерисовки.

Заключение по управлению состоянием

Состояние в Lit управляется через реактивные свойства, локальные состояния и методы жизненного цикла. Внимательное использование декораторов @property и @state, правильное обновление массивов и объектов, а также реакция на события и атрибуты создают стабильные, легко расширяемые компоненты с минимальными издержками на рендеринг.

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