柔軟で再利用可能なUIコンポーネント設計パターン
従来のアプローチ ❌
<Accordion
items={[
{ title: "...", content: "..." },
{ title: "...", content: "..." },
]}
/>props で全てのデータを渡す必要がある
Compound Components ✅
<Accordion>
<AccordionItem title="...">
コンテンツ
</AccordionItem>
<AccordionItem title="...">
コンテンツ
</AccordionItem>
</Accordion>子コンポーネントで柔軟に構成
代表的なライブラリでの採用例:
// Context の作成
const AccordionContext = createContext<{
activeIndex: number | null;
setActiveIndex: (i: number) => void;
} | null>(null);
// 親コンポーネント
function Accordion({ children }) {
const [activeIndex, setActiveIndex]
= useState<number | null>(null);
return (
<AccordionContext.Provider
value={{ activeIndex, setActiveIndex }}
>
{children}
</AccordionContext.Provider>
);
}// カスタムフック
function useAccordion() {
const context = useContext(AccordionContext);
if (!context) {
throw new Error(
"AccordionItem must be used within Accordion"
);
}
return context;
}
// 子コンポーネント
function AccordionItem({ title, children, index }) {
const { activeIndex, setActiveIndex }
= useAccordion();
const isOpen = activeIndex === index;
return (
<div onClick={() => setActiveIndex(index)}>
{title}
{isOpen && children}
</div>
);
}他の中級・上級サンプルもぜひご覧ください。
カタログを見る