Лестница композиции в React: как не утонуть в пропсах и оверинжиниринге 🧗♂️
Четыре уровня композиции React от Orus: обычные пропсы, compound-компоненты, Composer с Providers и стейт за контрактом.

По мере роста проекта любой фронтенд упирается в одну из двух крайностей: либо компоненты разрастаются до десятков пропсов (isCollapsed, leadingIcon, customTitle и т.д.), либо разработчики сходу заворачивают всё в глобальные провайдеры и контексты.
Команда Orus опубликовала отличную статью о том, как они упорядочили композицию компонентов в виде «лестницы абстракций» из 4 ступеней. Главное правило: начинать всегда с самого дешевого нижнего уровня и подниматься выше только тогда, когда появляется конкретная боль.
Вот как выглядит их лестница:
- Plain Props (Обычные пропсы) Базовый уровень, на котором должно оставаться подавляющее большинство UI-компонентов. Чистая функция от пропсов без магии.
- Compound Components (Составные компоненты)
Когда компонент начинает обрастать флагами на каждый чих, вместо пропсов вроде
leadingилиtrailingвводятся слоты и compound-структура (Item.Root,Item.Media). Компонент отвечает за сетку и стили, но отдаёт управление содержимым наверх. - Composer + Providers (Разделение UI и данных)
Включается, когда один и тот же UI должен отображать данные из разных источников (например, список активных сделок, архивных или моков в тесах). Верстка выносится в
Composer(читает контракт данных и не знает, откуда они пришли), а данные прокидываются через заменяемыеProviders. - Lifted State behind a Contract (Вынос стейта за контракт) Вершина лестницы, когда сложный интерактивный стейт выносится за границы UI-компонента через интерфейс/контракт, сохраняя сам лейаут «чистым».
Когда НЕ нужно подниматься по лестнице:
- Ради «единообразия» (когда все фичи пытаются подогнать под одну архитектурную гребенку).
- Если источник данных ровно один и альтернатив в обозримом будущем не предвидится.
- Для локального стейта, который не выходит за пределы компонента.