Higher-Order Components (HOC) — это архитектурный приём, при котором функция принимает компонент и возвращает новый компонент с расширенным поведением. В Stencil данный подход применяется не в классическом виде, как в React, а адаптируется под специфику компилятора, Web Components и декораторной модели.
Stencil ориентирован на генерацию стандартных Web Components, поэтому HOC здесь не являются частью официального API, но активно используются как паттерн для переиспользования логики, кросс-компонентных возможностей и инкапсуляции поведения.
Ключевые различия обусловлены архитектурой:
В результате Higher-Order Components в Stencil чаще реализуются как:
Общая схема:
Пример концептуальной структуры:
type StencilComponent<T> = new (...args: any[]) => T;
function withSomething<T extends StencilComponent<any>>(Base: T) {
return class extends Base {
// дополнительная логика
};
}
Такой подход позволяет внедрять повторяющееся поведение без копирования кода.
Stencil предоставляет фиксированный набор хуков жизненного цикла:
componentWillLoadcomponentDidLoadcomponentWillRendercomponentDidRendercomponentWillUpdatecomponentDidUpdatedisconnectedCallbackHOC может перехватывать эти методы, сохраняя оригинальное поведение.
function withLogging<T extends new (...args: any[]) => any>(Base: T) {
return class extends Base {
async componentWillLoad() {
if (super.componentWillLoad) {
await super.componentWillLoad();
}
console.log('Component will load');
}
};
}
Ключевые моменты:
super;Stencil не поддерживает контекст в стиле React, но HOC может внедрять
состояние через @State.
import { State } from '@stencil/core';
function withLoadingState<T extends new (...args: any[]) => any>(Base: T) {
return class extends Base {
@State() loading = false;
setLoading(value: boolean) {
this.loading = value;
}
};
}
Результат:
HOC может добавлять вычисляемые свойства, методы и вспомогательную логику.
Пример внедрения форматирования данных:
function withFormatter<T extends new (...args: any[]) => any>(Base: T) {
return class extends Base {
formatDate(date: Date): string {
return date.toISOString().split('T')[0];
}
};
}
Такой подход особенно полезен для:
HOC легко комбинируются:
const EnhancedComponent = withLogging(
withLoadingState(
withFormatter(MyComponent)
)
);
При этом важно учитывать порядок:
Stencil использует декораторы:
@Component@Prop@State@Event@Method@WatchHOC не может динамически добавлять декораторы после компиляции. Все декораторы должны быть известны компилятору на этапе анализа кода.
Следствия:
@Prop нельзя добавить условно;@Component;Корректный порядок:
const Enhanced = withLoadingState(BaseComponent);
@Component({
tag: 'my-component',
shadow: true
})
export class MyComponent extends Enhanced {}
Миксины в TypeScript часто используются в Stencil. HOC фактически является их функциональным вариантом.
Сравнение:
Миксин
HOC
Оба подхода могут использоваться совместно.
Основные ограничения:
@Prop и
@Event.Рекомендации:
Типичные кейсы:
HOC особенно эффективны в:
Higher-Order Components формируют слой абстракции между инфраструктурой и конкретными компонентами. Они позволяют:
В экосистеме Stencil HOC не являются обязательным инструментом, но при грамотном использовании становятся мощным архитектурным приёмом, дополняющим декораторы, миксины и сервисные слои.