Фреймворк Lit использует реактивную модель обновления интерфейса,
основанную на наблюдаемых свойствах (@property) и шаблонах
HTML (html template literals). Когда значение свойства
изменяется, Lit автоматически инициирует процесс рендеринга компонента.
Рендеринг в Lit выполняется через виртуальный DOM-подобный механизм,
который минимизирует изменения в реальном DOM, сравнивая старую и новую
разметку шаблона.
Ключевым элементом является метод
render(), возвращающий шаблон, обычно оформленный
через html:
import { LitElement, html, css } from 'lit';
import { property } from 'lit/decorators.js';
class MyComponent extends LitElement {
@property({ type: String }) name = 'Lit';
render() {
return html`<p>Hello, ${this.name}!</p>`;
}
}
customElements.define('my-component', MyComponent);
Изменение свойства name автоматически инициирует
обновление шаблона.
1. Установка свойства hasChanged
Каждое свойство может иметь кастомную функцию
hasChanged, которая определяет, будет ли перерисовываться
компонент при изменении значения:
@property({ type: Number, hasChanged: (newVal, oldVal) => newVal > oldVal })
count = 0;
В этом примере компонент обновляется только тогда, когда новое
значение count больше старого. Это позволяет игнорировать
ненужные изменения и снижает нагрузку на DOM.
2. Разделение компонентов
Часто оптимальнее создавать мелкие компоненты, каждый из которых отвечает за свою часть интерфейса. Lit обеспечивает локальное рендерирование, что значит: если изменяется свойство одного компонента, его соседние элементы не ререндерятся.
class UserCard extends LitElement {
@property({ type: Object }) user;
render() {
return html`<p>${this.user.name}</p>`;
}
}
customElements.define('user-card', UserCard);
Даже если родительский компонент обновляется, дочерние
UserCard будут перерисованы только при изменении свойства
user.
3. Использование requestUpdate с
условием
Метод requestUpdate позволяет вручную контролировать,
когда компонент должен обновляться. Можно передавать имя свойства и
старое значение:
this.requestUpdate('name', oldValue);
Это предотвращает автоматический ререндеринг при изменении несущественных данных.
1. Использование repeat для списков
Для рендеринга массивов используется директива repeat из
lit/directives/repeat.js, которая позволяет повторно
использовать элементы DOM при обновлении массива:
import { repeat } from 'lit/directives/repeat.js';
render() {
return html`
<ul>
${repeat(this.items, item => item.id, item => html`<li>${item.name}</li>`)}
</ul>
`;
}
Это значительно быстрее, чем простая переборка массива через
map, так как Lit идентифицирует элементы по ключу и
обновляет только изменённые.
2. Ленивая загрузка подшаблонов
Если часть интерфейса не всегда видна, можно использовать директиву
when из lit/directives/when.js для условного
рендеринга:
import { when } from 'lit/directives/when.js';
render() {
return html`
${when(this.showDetails, () => html`<p>Подробная информация</p>`)}
`;
}
Элемент рендерится только если условие истинно, что экономит ресурсы браузера.
3. Минимизация вычислений в шаблоне
Вычисления внутри шаблона выполняются при каждом ререндере. Для оптимизации следует предварительно вычислять значения в методах или геттерах:
get formattedName() {
return this.name.toUpperCase();
}
render() {
return html`<p>${this.formattedName}</p>`;
}
Это снижает нагрузку на шаблон при частых обновлениях.
Lit позволяет использовать static styles для CSS, что
исключает повторное внедрение стилей при каждом ререндере:
static styles = css`
p {
color: blue;
}
`;
Стили загружаются один раз и применяются ко всем экземплярам компонента. Для динамических изменений предпочтительно использовать CSS-переменные вместо пересоздания стилей.
Для анализа производительности можно использовать встроенные средства
браузера, профилировщик и directive cache
из lit/directives/cache.js:
import { cache } from 'lit/directives/cache.js';
render() {
return html`${cache(this.contentTemplate)}`;
}
cache сохраняет предыдущий результат рендера и повторно
вставляет его в DOM, если шаблон не изменился.
Основные принципы оптимизации рендеринга в Lit сводятся к:
hasChanged, requestUpdate).repeat, when).cache) для статических или редко меняющихся частей
DOM.Следование этим принципам позволяет создавать интерфейсы с высокой производительностью даже при сложных структурах данных и частых обновлениях.