Haunted — это современная библиотека для создания веб-компонентов на базе Web Components и Hooks, вдохновлённая подходом React. Одной из ключевых особенностей является возможность эффективного управления множественными рендерами компонентов, что особенно важно для сложных интерфейсов с динамическими данными.
В Haunted любой компонент — это функция, возвращающая шаблон, обычно
с использованием html из haunted:
import { html, component } from 'haunted';
function Counter({ value = 0 }) {
return html`
<div>
<p>Значение: ${value}</p>
</div>
`;
}
customElements.define('my-counter', component(Counter));
Каждый вызов функции компонента может инициировать новый рендер. Haunted использует виртуальный DOM внутри шаблонов lit-html, поэтому изменения в состоянии автоматически обновляют только изменившиеся части DOM, минимизируя накладные расходы.
renderПри работе с несколькими экземплярами компонента или повторным вызовом рендера одного и того же компонента важно понимать, что:
component() создаёт новый класс
веб-компонента.Пример множественных рендеров:
import { html, component, useState } from 'haunted';
function MultiCounter() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
return html`
<div>
<button @click=${() => setCount1(count1 + 1)}>Increment 1</button>
<p>Первый счётчик: ${count1}</p>
<button @click=${() => setCount2(count2 + 1)}>Increment 2</button>
<p>Второй счётчик: ${count2}</p>
</div>
`;
}
customElements.define('multi-counter', component(MultiCounter));
Каждое нажатие кнопки вызывает локальный рендер соответствующего счётчика, не затрагивая другой.
Haunted предоставляет несколько подходов для минимизации избыточных рендеров:
useState или useReducer для разных частей
интерфейса. Это предотвращает ненужное обновление всего компонента при
изменении одной части состояния.useMemo или
cache:import { html, component, useMemo, useState } from 'haunted';
function ExpensiveRender({ data }) {
const expensiveTemplate = useMemo(() => {
return html`<p>Обработанные данные: ${data.map(d => d * 2)}</p>`;
}, [data]);
return html`<div>${expensiveTemplate}</div>`;
}
customElements.define('expensive-render', component(ExpensiveRender));
useMemo предотвращает пересоздание тяжёлого шаблона,
если зависимости не изменились.
Haunted поддерживает работу с асинхронными данными напрямую в шаблонах:
import { html, component, useState, useEffect } from 'haunted';
function AsyncDataComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/items')
.then(res => res.json())
.then(setData);
}, []);
return html`
<div>
${data ? html`<ul>${data.map(item => html`<li>${item.name}</li>`)}</ul>` : html`<p>Загрузка...</p>`}
</div>
`;
}
customElements.define('async-data', component(AsyncDataComponent));
Каждое изменение состояния data инициирует
отдельный рендер, при этом Haunted обновляет только
необходимые узлы DOM.
shouldUpdateHaunted позволяет ограничивать рендеры через переопределение метода
shouldUpdate в компоненте:
function ConditionalRender({ value }) {
return html`<p>Значение: ${value}</p>`;
}
const ConditionalComponent = component(ConditionalRender, {
observedAttributes: ['value'],
shouldUpdate: (el, changedProps) => changedProps.has('value') && changedProps.get('value') % 2 === 0
});
customElements.define('conditional-render', ConditionalComponent);
В этом примере компонент будет обновляться только тогда, когда
value чётное, предотвращая лишние рендеры
при других изменениях.
При работе с динамическими списками особенно важно контролировать
идентичность элементов. Haunted использует ключи
(key) через repeat из lit-html:
import { html, component } from 'haunted';
import { repeat } from 'lit-html/directives/repeat.js';
function TodoList({ items }) {
return html`
<ul>
${repeat(items, item => item.id, item => html`<li>${item.text}</li>`)}
</ul>
`;
}
customElements.define('todo-list', component(TodoList));
repeat обеспечивает минимальное количество изменений DOM
при добавлении, удалении или обновлении элементов списка, даже если
компонент рендерится многократно.
useMemo, repeat и
shouldUpdate позволяет оптимизировать
производительность.Haunted сочетает в себе гибкость Web Components с эффективной системой обновления интерфейса, делая множественные рендеры управляемыми и предсказуемыми.