「props地獄」を卒業しよう。コンポーネント合成(Composition)で実現する、疎結合なUIアーキテクチャ
現場でReactを書いていると、一度は経験するはずだ。「Props Drilling(プロップス・ドリリング)」。親から子、子から孫へと、バケツリレーのようにデータを渡すあの忌々しい作業。
「いや、Contextを使えばいいじゃん」――確かにそうかもしれない。だが、闇雲にContextへ逃げるのは、実は設計の敗北を意味することもある。
今日は、Reactにおける最も強力で、かつ最も誤解されやすい概念の一つ、「コンポーネント合成(Composition)」と`children`の活用について、現場の視点から深く掘り下げよう。
—
なぜ `children` なのか?ブラウザの裏側と設計思想
多くの初級者が「`children`は単なるDOMの入れ物」と捉えがちだが、Reactにおける`children`は、コンポーネントの「穴(スロット)」だ。
ブラウザのレンダリングエンジンは、`children`がどう構成されようと、最終的にはフラットなDOMツリーを構築する。しかし、Reactの仮想DOMレベルでは、`children`を活用することで「何を表示するか」の責務を親コンポーネントに委譲し、ラッパーコンポーネントを「どう表示するか」というプレゼンテーションに専念させることができる。
これこそが、疎結合なアーキテクチャの真骨頂だ。
実践:Layoutラッパーの作り方
よくある「カードUI」を例にしよう。ヘッダーやフッター、背景色を持つコンポーネントを、毎回propsでカスタマイズしていませんか? それ、`children`を使えばもっとエレガントに書ける。
import React, { ReactNode } from ‘react’;
// CardのProps定義:childrenを必須にするのがポイント
type CardProps = {
title: string;
children: ReactNode; // ReactNodeは、JSX、文字列、数値など何でも許容する最強の型
};
export const Card = ({ title, children }: CardProps) => {
return (
{title}
{/ ここに渡されたコンポーネントが展開される /}
);
};
なぜこれが「良い」のか?
- 再利用性: `Card`は中身の仕様を一切知らない。ただ「枠」として機能するだけだ。
- 保守性: 中身のUIが変わっても、`Card`コンポーネントを修正する必要はない。
- 疎結合: `Card`と中身のコンポーネントが依存関係を持たないため、テストも非常に楽になる。
—
さらに一歩先へ:「スロットパターン」の活用
もし、表示領域が複数ある場合はどうするか? 現場では、複数の`children`的なプロパティ(スロット)を定義する手法がよく使われる。
type LayoutProps = {
header: ReactNode;
main: ReactNode;
footer?: ReactNode; // フッターはオプションかもしれない
};
export const AppLayout = ({ header, main, footer }: LayoutProps) => {
return (
{footer &&
}
);
};
// 利用側のコード
const MyPage = () => (
main={
footer={
/>
);
この手法を使えば、無理に階層を深くしてPropsを渡す必要は一切なくなる。「Props Drilling」が起きるのは、大抵の場合、コンポーネントが「親に依存しすぎている」からだ。
—
シニアからのTips:ここだけは注意しろ
最後に、実務でハマりやすいポイントを共有しておく。
1. `children`の型には`ReactNode`を使え: `JSX.Element`と書く人がいるが、それだとテキストノードや配列を弾いてしまうことがある。`ReactNode`が最も柔軟で安全だ。
2. 型安全を忘れるな: `React.FC`(FunctionComponent)の型定義を使う場合、React 18以降は`children`が暗黙的に含まれなくなった。明示的に`type`や`interface`で定義する癖をつけよう。
3. 過剰なラップは禁物: なんでもかんでもコンポーネント合成すればいいわけじゃない。あまりに細分化しすぎると、今度は「どこで何がレンダリングされているか」を追うのが困難になる。バランスこそが設計の醍醐味だ。
まとめ
コンポーネント合成は、Reactの最も「Reactらしい」書き方だ。
`children`を単なる「プロパティの一部」ではなく、「コンポーネントの柔軟な拡張ポイント」として意識するだけで、君の書くコードの質は劇的に変わるはずだ。
綺麗なコンポーネント設計は、チームの寿命を延ばす。さあ、明日のプルリクから、不要なpropsのバケツリレーを削除して、もっと自由な合成を楽しもうぜ。
もし分からないことがあれば、いつでもコードを見せに来てくれ。一緒に最高にクールなUIを作り上げよう。

コメント