合成で組み立てる
props を足して分岐を増やす行き止まり
Layout に「横に絞り込みを出したい」と言われたとします。素直にやると props が増えます。
type LayoutProps = {
title: string;
itemCount: number;
showSide: boolean;
sideKind: "category" | "price";
};このやり方は必ず行き詰まります。画面が1つ増えるたびに真偽値と分岐が増え、Layout は「どの画面から呼ばれたか」を全部知っている部品になります。枠が中身を知っているほど、枠は使い回せなくなります。
穴を空けて、外から差す
代わりに、Layout には中身の代わりに穴だけを持たせます。穴の型は ReactNode です。第1章の children と同じもので、画面に出せるものなら何でも入ります。
import type { ReactNode } from "react";
type LayoutProps = {
header: ReactNode;
side: ReactNode;
children: ReactNode;
};
export function Layout({ header, side, children }: LayoutProps) {
return (
<div className="layout">
<header className="layout-header">{header}</header>
<div className="layout-body">
<aside className="layout-side">{side}</aside>
<main className="layout-main">{children}</main>
</div>
</div>
);
}穴が2つ以上あるときは、真ん中の主役を children にして、残りを名前付きの props にするのが読みやすい形です。
呼ぶ側で組み立てる
<Layout header={<h1>fleama</h1>} side={<CategoryNav />}>
{items.map((item) => (
<ItemCard key={item.id} item={item} />
))}
</Layout>これを合成と呼びます。Layout は CategoryNav も ItemCard も知りません。知らないから、別の画面では別のものを差せます。真偽値の props が増えそうになったら、まず穴に置き換えられないかを考えます。
演習
Layout を、header と side と children の3つの穴を持つ形に組み直します。