Как в гексагональной архитектуре разместить клиентское приложение на React?
Основы React
В гексагональной архитектуре (ports & adapters) React-приложение занимает место адаптера — это внешний слой, «драйвер», через который пользователь взаимодействует с ядром домена.
Расстановка слоёв
[React UI] → порт (интерфейс) → [ядро: домен + use cases] → порт → [адаптеры инфраструктуры: HTTP, storage]- Ядро — чистый TypeScript без React: доменные модели, бизнес-правила, use cases. Не знает ни про компоненты, ни про fetch.
- Порты — интерфейсы, которыми ядро общается с миром:
OrderRepository,PaymentGateway(выходные),PlaceOrder(входные). - React — входной адаптер: компоненты вызывают use cases и отображают результат; вся вёрстка, состояние UI, роутинг — здесь.
- Инфраструктурные адаптеры: реализация портов поверх HTTP-клиента, localStorage, WebSocket.
Как это выглядит в коде
src/
core/ // ядро: НИКАКИХ импортов React
domain/ usecases/ ports/
adapters/
api/ // OrderRepositoryHttp implements OrderRepository
ui/ // React: компоненты, хуки, роутингСвязывание — через DI: адаптеры создаются на старте и передаются в ядро (фабрика/контекст). React-хуки — тонкая прослойка: useCheckout() вызывает use case и маппит результат в state.
Практические правила
- Направление зависимостей: ui → core, api → core; core не импортирует ничего из адаптеров.
- Бизнес-логика не живёт в компонентах/хуках — они только оркеструют вызовы и отображают.
- Ядро тестируется юнитами без DOM; React — отдельно, с мок-портами.
- Не перегибать: для CRUD-приложений полная гексагональность избыточна — паттерн окупается при богатой доменной логике.
Коротко для собеседования
React — внешний адаптер (driving adapter): ядро — чистый TS с доменом, use cases и портами-интерфейсами; React вызывает use cases через тонкие хуки, инфраструктура реализует порты (HTTP, storage). Зависимости только внутрь (ui/api → core), логика не в компонентах; тестируется ядро без React.