合成で組み立てる

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つの穴を持つ形に組み直します。

ヒント

App.tsx
CategoryNav.tsx
ItemCard.tsx
Layout.tsx
types.ts
App.tsx
CategoryNav.tsx
ItemCard.tsx
Layout.tsx
types.ts
プレビュー

できているか

  • 上の帯に fleama が出ている
  • 横の帯がある
  • 横の帯にカテゴリが3つ出ている
  • 真ん中にカードが3枚ある
  • 3枚とも価格が出ている
  • 帆布トートが出ている