Higher-Order Components (HOC) в Haunted
Higher-Order Component трактуется как функция, принимающая веб-компонент и возвращающая новый компонент, обогащённый дополнительным поведением. Подобный паттерн способствует выделению общего функционала и его повторному использованию без наследования или дублирования.
HOC рассматривается как чистая функция: исходный компонент остаётся
неизменным, а расширение происходит за счёт композиции. Haunted
предоставляет удобный способ оборачивать функциональные компоненты,
сохраняя реактивность и хуки. В качестве входных данных выступает
компонент, использующий html и хуки (useState,
useEffect), а в качестве результата возникает новый
компонент с изменёнными пропсами, контекстом или логикой обновления.
Прозрачность для пропсов Исходные пропсы передаются внутрь без модификации, либо дополняются. Подчёркивается отсутствие связности между HOC и конкретной реализацией компонента.
Чистота композиции Не изменяется прототип и не применяется наследование. Расширение реализуется исключительно через функции.
Инкапсуляция общего поведения Повторяющиеся побочные эффекты, синхронизация состояния или взаимодействие с внешними API скрываются внутри HOC.
Совместимость с хуками HOC может использовать собственные хуки и обеспечивать компоненты дополнительными состояниями или эффектами.
Создание HOC сводится к объявлению функции, принимающей компонент и возвращающей новую функциональную сущность:
import { component, html, useState } from 'haunted';
function withCounter(Base) {
function Wrapped(props) {
const [count, setCount] = useState(0);
return html`
<div>
<button @click=${() => setCount(count + 1)}>+</button>
<span>${count}</span>
${Base(props)}
</div>
`;
}
return component(Wrapped);
}
Ключевой момент: Base вызывается как функция, что
подчёркивает функциональную природу компонентов Haunted и отсутствие
необходимости в классовой обёртке.
Добавление пропсов HOC может подмешивать вычислённые значения или внешние зависимости:
function withTimestamp(Base) {
return component(props => {
const timestamp = Date.now();
return Base({ ...props, timestamp });
});
}
Переопределение поведения Расширение способно изменять порядок рендера, отсекать пропсы или оптимизировать обновления. Например, HOC может предотвращать лишние рендеры при неизменности входных данных.
Функциональный рендер Haunted означает, что компонент вызывается на каждое обновление состояния. HOC обслуживает этот вызов, сохраняя собственное состояние и эффекты. Важно, что порядок вызова хуков внутри Wrapped-компонента строго фиксирован. Это диктует аккуратность при условных вызовах HOC и внутри HOC.
Передача состояния вниз формирует цепочку реактивности: изменение в
HOC вызывает обновление дочернего компонента. Состояния оказываются
независимыми, что облегчает их тестирование и снижает связанность. Если
HOC взаимодействует с внешним источником данных (например, WebSocket),
подписка и отписка должны располагаться внутри
useEffect.
HOC в Haunted выполняют роль декораторов без синтаксического сахара, сохраняя композиционный стиль. В отличие от миксинов, они не встраивают методы в компонент, а формируют над ним функциональную обёртку. По сравнению с классическими декораторами веб-компонентов, подход Haunted является менее императивным и более предсказуемым с точки зрения рендера.
HOC удобно используют общий контекст или локальный стор. Через хуки возможно внедрение состояния контекста в компонент без его прямого участия. Это делает HOC инструментом интеграции сервисов или моделей данных.
Комбинирование нескольких HOC обычно производится через последовательное применение:
const Enhanced = withTimestamp(withCounter(Base));
Последовательность определяет способ прохождения пропсов и реактивности. Применение HOC выстраивает слой функционального декорирования вокруг базового компонента, создавая модульную архитектуру, где каждый слой отвечает за конкретный аспект поведения.
Higher-Order Components вписываются в экосистему Haunted как гибкий механизм расширения функциональных веб-компонентов. Преимущества заключаются в композиционности, предсказуемости, разделении ответственности и аккуратной работе с хуками. Паттерн оказывает значительное влияние на структурирование кода, улучшает читаемость и способствует созданию переиспользуемых абстракций.