Kodokon kodokon.com

コンポジション: children とコンポーネントへの分割

children prop を使って再利用可能なコンテナコンポーネントを作り、画面を明確な責務ごとに分割します。

6 分 · 3 問

このレッスンを Kodokon で開く

自分の内容を前もって知らないコンポーネントもあります。カード、モーダルウィンドウ、レイアウトなどです。React はこれを特別な children prop で解決します。コンポーネントの開始タグと終了タグの間に置いたものはすべてそのコンポーネントに渡され、好きな場所に挿入できるようになります。コンテナが枠組みを担い、呼び出し側が中身を提供します。

JSX
function Card({ children }) {
  return <section className="card">{children}</section>;
}

function App() {
  return (
    <Card>
      <h2>Invoice #1024</h2>
      <p>Amount: €49.90</p>
    </Card>
  );
}
Card は中身が何かを知らずに、任意の内容を枠で囲みます。

1 つのスロットでは足りないときは、名前付き props を通じて JSX を渡します。タイトル、フッター、アクションバーなどです。prop は他のどんな値と同じように React 要素を受け取れます。こうして、それぞれ明確に名付けられた複数の「スロット」が得られます。

JSX
function Modal({ title, footer, children }) {
  return (
    <div className="modal">
      <header>{title}</header>
      <div className="modal-body">{children}</div>
      <footer>{footer}</footer>
    </div>
  );
}
3 つの異なるスロット: title、children、footer。

コンポジションは分割の指針にもなります。コンポーネントは 1 つの識別できる責務を持つべきです。ユーザーの行を表示する、リストをレイアウトする、といったように。コンポーネントが複数の役割を抱え込んだらすぐに、サブコンポーネントを抽出しましょう。それぞれが短くなり、テストしやすくなり、別の場所でも再利用できるようになります。

JSX
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <UserRow key={user.id} user={user} />
      ))}
    </ul>
  );
}

function UserRow({ user }) {
  return (
    <li>
      <strong>{user.name}</strong> - {user.email}
    </li>
  );
}
各コンポーネントが単一の責務を保ちます。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. コンポーネントの children prop は何を受け取りますか?
    • 同じファイル内で宣言された子コンポーネントのリスト
    • 開始タグと終了タグの間に置かれたすべてのもの
    • 親コンポーネントから渡された props
  2. children 以外の prop で JSX を渡せますか?
    • はい、React 要素は他の値と同じ値です
    • いいえ、children prop だけが JSX を受け取れます
    • はい、ただし HTML を含む文字列としてのみ
  3. コンポーネントを分割すべきだと最も確実に示すサインはどれですか?
    • コードが 20 行を超えている
    • 複数の useState を使っている
    • レンダリング内で複数の異なる責務を組み合わせている