Chakra UI предоставляет мощные инструменты для построения модульных и переиспользуемых компонентов, что особенно важно при работе с крупными приложениями. Основная идея составных компонентов заключается в разделении логики и визуальной структуры на независимые, но взаимосвязанные элементы, которые можно комбинировать.
Составной компонент обычно строится вокруг контейнерного
компонента, который управляет состоянием и передает данные
своим дочерним элементам через props или React Context. Это
позволяет:
Пример контейнера с передачей состояния дочерним элементам через
props:
import { Box, Button, Text } from "@chakra-ui/react";
import { useState } from "react";
function Toggle({ children }) {
const [on, setOn] = useState(false);
const toggle = () => setOn(!on);
return children({ on, toggle });
}
export default function Example() {
return (
<Toggle>
{({ on, toggle }) => (
<Box>
<Button onCl ick={toggle}>Переключить</Button>
<Text>{on ? "Включено" : "Выключено"}</Text>
</Box>
)}
</Toggle>
);
}
Здесь Toggle выступает как контейнер, а дочерние элементы получают управляемое состояние через функцию.
Для более сложных составных компонентов часто используют
React.createContext. Chakra UI отлично интегрируется с этим
подходом, обеспечивая чистый и декларативный API.
Пример создания контекста:
import { createContext, useContext, useState } from "react";
import { Box, Button } from "@chakra-ui/react";
const AccordionContext = createContext();
function Accordion({ children }) {
const [openIndex, setOpenIndex] = useState(null);
return (
<AccordionContext.Provider value={{ openIndex, setOpenIndex }}>
<Box>{children}</Box>
</AccordionContext.Provider>
);
}
function AccordionItem({ index, title, children }) {
const { openIndex, setOpenIndex } = useContext(AccordionContext);
const isOpen = openIndex === index;
return (
<Box borderWidth="1px" borderRadius="md" mb={2}>
<Button width="100%" onCl ick={() => setOpenIndex(isOpen ? null : index)}>
{title}
</Button>
{isOpen && <Box p={4}>{children}</Box>}
</Box>
);
}
export default function App() {
return (
<Accordion>
<AccordionItem index={0} title="Первый элемент">
Содержимое первого элемента
</AccordionItem>
<AccordionItem index={1} title="Второй элемент">
Содержимое второго элемента
</AccordionItem>
</Accordion>
);
}
Этот подход позволяет изолировать состояние каждого элемента и при этом управлять всей группой через контекст.
forwardRef для совместимости с Chakra UIДля создания более интегрированных составных компонентов важно
поддерживать передачу ref. Chakra UI активно использует
ref для управления фокусом, анимациями и доступностью.
Пример с forwardRef:
import { forwardRef } from "react";
import { Box } from "@chakra-ui/react";
const Card = forwardRef(({ children, ...props }, ref) => (
<Box ref={ref} borderWidth="1px" borderRadius="md" p={4} {...props}>
{children}
</Box>
));
export default Card;
Использование forwardRef позволяет родительским
компонентам обращаться к DOM-элементам дочернего компонента напрямую,
что особенно полезно для интерактивных виджетов.
useStyleConfigСоставные компоненты легко настраиваются с помощью системы
стилей Chakra UI. Для переиспользуемости рекомендуется
использовать useStyleConfig или chakra для
обертки базовых элементов.
Пример:
import { Box, useStyleConfig } from "@chakra-ui/react";
function CustomButton(props) {
const styles = useStyleConfig("Button", props);
return <Box as="button" sx={styles} {...props} />;
}
Это позволяет создавать единый стиль компонентов в соответствии с дизайн-системой, сохраняя гибкость для специфических вариантов.
Составные компоненты часто требуют передачи
коллбеков вниз по иерархии или получения уведомлений от
дочерних компонентов. Для этого применяются props типа
onChange, onSelect,
onToggle, что позволяет централизованно
обрабатывать события.
function CheckboxGroup({ onChange, children }) {
const [selected, setSelected] = useState([]);
const toggleItem = (value) => {
const newSelected = selected.includes(value)
? selected.filter((v) => v !== value)
: [...selected, value];
setSelected(newSelected);
onChange?.(newSelected);
};
return children({ selected, toggleItem });
}
Этот подход делает компоненты модульными и независимыми, но при этом легко управляемыми.
Chakra UI предоставляет Collapse, Fade,
ScaleFade, Slide, которые отлично сочетаются с
составными компонентами для создания интерактивных и плавных
интерфейсов.
Пример:
import { Collapse, Button, Box } from "@chakra-ui/react";
import { useState } from "react";
function AnimatedPanel() {
const [show, setShow] = useState(false);
return (
<Box>
<Button onCl ick={() => setShow(!show)}>Переключить</Button>
<Collapse in={show} animateOpacity>
<Box p={4} mt={2} bg="gray.100" rounded="md">
Анимированное содержимое
</Box>
</Collapse>
</Box>
);
}
Комбинация составных компонентов и анимаций позволяет создавать продвинутые интерфейсы без нарушения принципов переиспользуемости и управления состоянием.
forwardRef для совместимости с Chakra UI.useStyleConfig для
согласованности визуального языка.Создание составных компонентов в Chakra UI — это сочетание декларативного React-подхода, гибкой системы стилей и удобной работы с состоянием, что позволяет строить интерфейсы любого уровня сложности, оставаясь при этом модульными и поддерживаемыми.