В библиотеке MUI (Material-UI) концепция compound components позволяет создавать более гибкие и настраиваемые компоненты, объединяя несколько связанных элементов в один интерфейс. Основная идея заключается в разделении логики и разметки: один компонент управляет состоянием, а вложенные компоненты отвечают за визуализацию и отдельные части интерфейса.
Примером может служить компонент Tabs. Он содержит
контейнер Tabs для управления состоянием активной вкладки и
дочерние компоненты Tab для отображения отдельных элементов
интерфейса.
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box';
import React, { useState } from 'react';
function BasicTabs() {
const [value, setValue] = useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<Box sx={{ width: '100%' }}>
<Tabs value={value} onCha nge={handleChange}>
<Tab label="Вкладка 1" />
<Tab label="Вкладка 2" />
<Tab label="Вкладка 3" />
</Tabs>
<Box sx={{ p: 2 }}>
{value === 0 && <div>Содержимое вкладки 1</div>}
{value === 1 && <div>Содержимое вкладки 2</div>}
{value === 2 && <div>Содержимое вкладки 3</div>}
</Box>
</Box>
);
}
Здесь Tabs выступает в роли управляющего компонента, а
Tab — дочернего, отвечающего за отдельные элементы
интерфейса. Такой подход позволяет сохранять согласованное состояние и
минимизировать повторение кода.
Разделение ответственности Управляющий компонент
отвечает за состояние и логику, а дочерние компоненты — за визуализацию.
Например, компонент Accordion управляет открытием и
закрытием панели, а AccordionSummary и
AccordionDetails отображают заголовок и содержимое
соответственно.
Использование контекста Для передачи состояния от родителя к дочерним элементам MUI активно использует React Context. Это позволяет дочерним компонентам получать данные без необходимости пробрасывать пропсы через каждый уровень иерархии.
import React, { createContext, useContext, useState } from 'react';
const AccordionContext = createContext();
function Accordion({ children }) {
const [expanded, setExpanded] = useState(false);
const toggle = () => setExpanded(prev => !prev);
return (
<AccordionContext.Provider value={{ expanded, toggle }}>
<div>{children}</div>
</AccordionContext.Provider>
);
}
function AccordionSummary({ children }) {
const { toggle } = useContext(AccordionContext);
return <div onCl ick={toggle}>{children}</div>;
}
function AccordionDetails({ children }) {
const { expanded } = useContext(AccordionContext);
return expanded ? <div>{children}</div> : null;
}
slot и slotProps,
которые позволяют заменять отдельные элементы и настраивать их
свойства.<Tabs
value={value}
onCha nge={handleChange}
slotProps={{
tab: { sx: { textTransform: 'none', fontWeight: 'bold' } }
}}
>
<Tab label="Первая вкладка" />
</Tabs>
Повторное использование логики Один управляющий компонент может работать с различными визуальными реализациями дочерних элементов, что повышает гибкость и уменьшает дублирование кода.
Согласованное состояние Compound components позволяют централизованно управлять состоянием, предотвращая рассинхронизацию элементов интерфейса.
Легкая кастомизация Через slot,
slotProps и sx можно менять стили и структуру
без изменения логики компонента.
slotProps позволяет динамически
изменять свойства дочерних компонентов в зависимости от состояния.<Tabs
value={value}
onCha nge={handleChange}
slotProps={{
tab: (tabIndex) => ({
sx: { color: value === tabIndex ? 'primary.main' : 'text.secondary' }
})
}}
>
<Tab label="Вкладка 1" />
<Tab label="Вкладка 2" />
</Tabs>
Контроль рендеринга дочерних компонентов Управляющий компонент может решать, какие элементы отображать, в зависимости от состояния или внешних условий. Это позволяет создавать адаптивные и интерактивные интерфейсы.
Композиция с другими компонентами MUI Compound
components легко интегрируются с другими элементами MUI, такими как
Box, Grid или Paper, что упрощает
построение сложных интерфейсов.
Для создания собственных compound components рекомендуется:
Такой подход обеспечивает гибкость, согласованность и масштабируемость интерфейсов, полностью соответствуя философии MUI — предоставлять мощные и настраиваемые компоненты без избыточной сложности.