Улучшаем дизайн React приложения с помощью Compound components

Сегодня я хочу рассказать про один не очень популярный, но очень классный паттерн в написании React приложений — Compound components.
Что это вообще такое
Compound components это подход, в котором вы объединяете несколько компонентов одной общей сущностью и общим состоянием. Отдельно от этой сущности вы их использовать не можете, тк они являются единым целым. Это как в BEM нельзя использовать E — элемент, отдельно от B — блока.
Самый наглядный пример такого подхода, который знают все фронты — это select с его option в обычном HTML.
В «сложном компоненте» может быть сколько угодно разных элементов и они могут быть использованы в любом порядке, но все равно их будет объединять одно поведение и одно состояние.
Когда вам нужно задуматься об использовании Compound components
Я могу выделить 2 ситуации, где этот подход отлично работает:
Когда у вас есть несколько отдельных компонентов, но они являются частью чего-то одного и объединены одной логикой (как select в HTML).
Например вам нужно сделать табуляцию, ясное дело, что по отдельности каждый таб вы использовать не будете и вот тут хорошо подойдет Compound components.
import React from 'react';
import { Tabs } from 'tabs';
function MyTabs() {
return (
console.log('Tab is changed')}>
Pie
Cake
Candies
Cookies
);
}
export default MyTabs;
По моему выглядит весьма лаконично, понятно и по реактовски) У нас есть возможность кастомизировать каждый отдельный таб, передать ему любые пропсы, а так же задать какие-то параметры для всех табов сразу, ну и внутри компонента Tabs может быть написана какая-то общая логика.
Сравните с тем, как это могло бы выглядеть без Compound components:
import React from 'react';
import { Tabs } from 'TabsWithoutCC';
function MyTabs() {
return (
console.log('Tab is changed')}
tabs={[
{ name: "Pie" },
{ name: "Cake", className: 'custom-tab' },
{ name: "Candies", disabled: true },
{ name: "Cookies" }
]}
/>
);
}
export default MyTabs;
А вот во втором варианте применения, как мне кажется, раскрывается вся мощь Compound Components.
Приведу пример из жизни: я делал форму аутентификации пользователя в банке, стандартно она должна выглядеть примерно так: есть поле ввода логина, пароля, у них должен быть тайтл, кнопка «войти», и нужно задать темную тему для всех компонентов, использовать эту форму будут на десктопах и в мобильном приложении через web-view
import React from 'react';
import { Form, Input, Button, Title } from 'our-design-system';
function AuthForm({ theme }) {
return (