Compound Components в Haunted
Подход compound components позволяет проектировать связанные элементы интерфейса как единое целое, сохраняя при этом высокую гибкость и выразительность API. В контексте библиотеки Haunted эта техника особенно удобна, поскольку Haunted соединяет функции, хуки и Web Components, обеспечивая чистую композицию без классовых наследований и тяжелой инфраструктуры.
Композитный компонент представляет сущность верхнего уровня (контейнер), которая содержит подкомпоненты (children) и управляет их поведением через контекст, пропсы и внутреннее состояние. Вместо передачи большого числа параметров каждому дочернему элементу, контейнер предоставляет согласованный интерфейс, а дочерние элементы используют этот интерфейс для координации.
Библиотека Haunted предоставляет механизм контекста через хук
useContext и API createContext. Это позволяет
контейнеру определить набор данных и методов и передать их вниз по
дереву. Каждый подкомпонент может подписаться на контекст, избегая
проп-дриллинга и утомительных цепочек передачи свойств.
Примерная структура:
Контейнер обычно инкапсулирует состояние, которое определяет
поведение всех дочерних компонентов. Для управления состоянием
используются хуки useState, useMemo,
useCallback и другие. Подкомпоненты не хранят критическое
для модели приложение состояние, а играют роль “представителей”
отдельного аспекта управления или отображения.
Ключевой момент: подкомпоненты могут быть переиспользуемыми, если не жёстко зависят от структуры контейнера. Для этого API контейнера должно быть минимальным, ясным и последовательным.
Хотя контекст закрывает большинство задач синхронизации, иногда
применяется событийная модель. Подкомпонент может генерировать
пользовательские события (CustomEvent) для уведомления
контейнера или соседних подкомпонентов. Haunted и Web Components
естественным образом поддерживают подобный механизм через DOM-события,
что снижает связность и повышает внеблочную переиспользуемость.
Техника compound components часто используется для:
Такие интерфейсы требуют множества взаимозависимых элементов, и Haunted позволяет выражать их декларативно, без избыточных классов и стейт-машин.
Хорошо спроектированный композитный компонент предоставляет понятный DSL. Например: контейнер объявляет структуру, а подкомпоненты внутри него определяются как слоты. Пользователь компонента может свободно комбинировать и переставлять подкомпоненты, не нарушая работу контейнера.
Пример принципов гибкого API:
Haunted использует lit-html для рендера, что дает диффинг и минимальные обновления. Композитные компоненты выигрывают от этого, поскольку изменения состояния контейнера не приводят к полной перерисовке всех подкомпонентов: перерисовываются только те, что используют изменившиеся данные.
Важный аспект: распределение состояния уменьшает количество ререндеров. Контейнер может мемоизировать значения и передавать их по контексту, что снижает перерендеринг дочерних элементов.
Каждый подкомпонент Haunted может быть оформлен как Custom Element, что дает:
Композитный компонент при этом не обязан иметь собственный shadow DOM: иногда предпочтительнее использовать “светлый” DOM для гибкой композиции.
Compound components в Haunted функционально напоминает подход из мира React, но адаптирован под Web Components. В отличие от HOC или mixin-подходов, здесь ключевой элемент — контекст и согласованный интерфейс. Нет необходимости расширять классы или создавать сложные структуры, что соответствует идеям функционального UI.
Тестирование упрощается благодаря тому, что основная логика находится в контейнере. Подкомпоненты можно тестировать отдельно, проверяя использование контекста и реакцию на события. Такое разделение делает интерфейсы понятными, а поведение — предсказуемым.
Практический вывод: compound components в Haunted оптимальны для UI, где множество элементов должны действовать сообща, оставаясь композиционно гибкими. Техника снижает связность, повышает переиспользуемость и улучшает читаемость структуры приложения.