Локальное состояние компонента является ключевым механизмом для управления динамическими данными внутри веб-компонента. В Lit локальное состояние позволяет хранить значения, которые влияют на отображение компонента, но не должны быть доступны извне через атрибуты или свойства элемента.
@stateВ Lit для объявления локального состояния используется декоратор
@state. Декоратор применяется к свойствам класса компонента
и автоматически отслеживает их изменения, вызывая повторный рендер при
обновлении значения.
import { LitElement, html } from 'lit';
import { state } from 'lit/decorators.js';
class CounterComponent extends LitElement {
@state()
private _count = 0;
render() {
return html`
<div>Счётчик: ${this._count}</div>
<button @click=${this._increment}>Увеличить</button>
`;
}
private _increment() {
this._count++;
}
}
customElements.define('counter-component', CounterComponent);
Особенности @state:
@state обычно делают приватными по
соглашению, используя префикс _.Изменение состояния должно происходить через присваивание значения
свойству с декоратором @state. Lit автоматически
определяет, что произошло обновление, и вызывает метод
requestUpdate() для повторного рендера. Если необходимо
выполнять дополнительные действия при обновлении, можно переопределить
метод updated(changedProperties):
updated(changedProperties) {
if (changedProperties.has('_count')) {
console.log(`Счётчик изменился с ${changedProperties.get('_count')} на ${this._count}`);
}
}
changedProperties содержит Map, где ключ — имя свойства,
а значение — его предыдущее состояние. Это удобно для реактивных
вычислений и синхронизации с внешними данными.
@property и @state@property используется для публичных свойств
компонента, которые могут связываться с атрибутами HTML и поддерживают
двунаправленное связывание с внешним миром.@state предназначен исключительно для внутреннего
состояния и не отражается в атрибутах.Использование @state улучшает инкапсуляцию, предотвращая
случайные внешние вмешательства в внутреннюю логику компонента.
Свойства с декоратором @state могут хранить любые типы
данных, включая объекты и массивы. При работе с ними важно создавать
новые экземпляры при изменении, чтобы Lit корректно отслеживал
обновления.
@state()
private _items = [];
_addItem(item) {
this._items = [...this._items, item];
}
Прямое изменение массива (this._items.push(item)) не
вызовет рендер, потому что Lit отслеживает изменение ссылки на объект, а
не его содержимое.
Использование локального состояния тесно связано с шаблонами Lit.
Любое свойство с @state, используемое внутри метода
render(), автоматически отслеживается. Это позволяет
строить динамические интерфейсы без ручного управления DOM.
render() {
return html`
<ul>
${this._items.map(item => html`<li>${item}</li>`)}
</ul>
<button @click=${() => this._addItem('Новый элемент')}>Добавить</button>
`;
}
Каждое изменение _items вызовет повторный рендер только
тех частей шаблона, которые зависят от _items, что
обеспечивает эффективное обновление интерфейса.
Локальное состояние удобно использовать в сочетании с
пользовательскими событиями. Компонент может изменять внутреннее
состояние и уведомлять внешние элементы через событие
CustomEvent:
private _increment() {
this._count++;
this.dispatchEvent(new CustomEvent('count-changed', {
detail: { count: this._count },
bubbles: true,
composed: true
}));
}
Это позволяет внутреннему состоянию оставаться инкапсулированным, но при необходимости взаимодействовать с другими компонентами.
@state использовать для приватных данных, не
предназначенных для связывания с HTML-атрибутами.Локальное состояние является основой реактивного поведения компонентов Lit и позволяет создавать высокоэффективные, динамические интерфейсы без лишнего кода и сложного управления DOM.