1. children
とは何か?
children
は、React コンポーネントに渡される特別な props のひとつです。
コンポーネントの 開始タグと終了タグのあいだに書かれた内容が、自動的に props.children
として渡されます。
function Box({ children }) {
return <div>{children}</div>;
}
<Box>
<p>Hello</p>
</Box>
このとき、Reactは以下のように props を解釈します:
{
children: <p>Hello</p>
}
つまり、React のコンポーネントを「箱」と見立てると、children
はその中に詰められた中身です。
- 親コンポーネントは「枠」や「構造」を定義
-
children
はその中に自由に詰め込める「内容」
この仕組みによって、コンポーネントの中身を外部から差し替えたり、再利用したりすることが可能になります。
2.children
の使い方パターン
パターン①:そのまま描画する(汎用ラッパー)
もっとも基本的な使い方。children
を単純にそのまま描画する。
function Container({ children }) {
return <div className="container">{children}</div>;
}
<Container>
<p>Hello</p>
</Container>
向いている場面
- カード、ボックス、レイアウト、モーダルなどの汎用 UI
- コンテンツに制限を持たせず自由に使いたいとき
パターン②:children
に処理を加える(map や wrap)
children
に共通の加工(ラップ、装飾など)を施す。
複数の子を処理する際には React.Children.map
を使用。
function List({ children }) {
return (
<ul>
{React.Children.map(children, child => (
<li>{child}</li>
))}
</ul>
);
}
<List>
<span>Apple</span>
<span>Banana</span>
</List>
向いている場面
- リストアイテム、ナビゲーション、複数要素の装飾
- コンテンツの個別レンダリングが必要な場面
パターン③:Function as Children(関数として子を渡す)
children
を関数として渡し、親が状態を与えてレンダリングを制御。
function MouseTracker({ children }) {
const [pos, setPos] = useState({ x: 0, y: 0 });
useEffect(() => {
const move = e => setPos({ x: e.clientX, y: e.clientY });
window.addEventListener("mousemove", move);
return () => window.removeEventListener("mousemove", move);
}, []);
return children(pos);
}
<MouseTracker>
{pos => <p>Mouse at {pos.x}, {pos.y}</p>}
</MouseTracker>
向いている場面
- 状態に応じたカスタム描画(例:グラフ、レスポンシブ対応)
- ロジックとUIを分離したいケース
パターン④:Compound Component(構造的スロット)
子要素を名前付きコンポーネント(スロット)として構造的に分けるパターン。
function Card({ children }) {
const header = React.Children.toArray(children).find(
c => c.type === Card.Header
);
const body = React.Children.toArray(children).find(
c => c.type === Card.Body
);
return (
<div>
<div className="card-header">{header}</div>
<div className="card-body">{body}</div>
</div>
);
}
Card.Header = ({ children }) => <>{children}</>;
Card.Body = ({ children }) => <>{children}</>;
<Card>
<Card.Header>タイトル</Card.Header>
<Card.Body>本文</Card.Body>
</Card>
向いている場面
- タブ、フォーム、モーダル、カードなどの複合 UI
- 設計の明確さ・保守性を求めるケース
3. children
の注意点と落とし穴
React公式ドキュメントでは次のように述べられています:
「
children
の使用は一般的ではなく、コードが壊れやすくなる可能性があります」
“It’s uncommon to usechildren
directly because it makes your code fragile.”
– React.dev - Passing Props
これは「children
自体を使うな」という意味ではなく、
children
の構造や順番に依存する設計をすると、脆くなるので注意せよという警告です。
落とし穴①:順番に依存した実装
function Layout({ children }) {
const header = children[0]; // 1番目を header と決め打ち
const content = children[1];
return (
<>
<header>{header}</header>
<main>{content}</main>
</>
);
}
なぜ危険?
- 子要素が1つだけだと
children
は配列ではなくなる(構文エラーの原因) - 呼び出し側が順番を間違えると崩れる
- 他の開発者が使う際に仕様がわかりにくい
落とし穴②:構造を前提にして children
をハードコード
function Item({ children }) {
return <li>{children}</li>;
}
<Item>
<span>Apple</span>
<span>Banana</span>
</Item>
なぜ危険?
-
<li>
の中に複数の要素が入ると HTML 構造的に不正になる可能性がある - ブラウザによっては正しく解釈されず意図しない表示になる
落とし穴③:children
の中身に型を仮定する
if (typeof children === 'string') {
// 文字列として処理
}
なぜ危険?
-
children
は JSX、配列、関数、null など様々な型を取りうる - このような分岐は意図しない挙動や壊れやすい設計につながる
4. 安全に扱うためには
① React.Children.map()
を使う
<ul>
{React.Children.map(children, child => (
<li>{child}</li>
))}
</ul>
- 子要素が単一でも複数でも一貫して処理可能
-
key
を指定することも可能 - 配列かどうかを気にせず扱える
② React.Children.toArray()
を使って明示的に配列化
const childArray = React.Children.toArray(children);
childArray.map(child => <div>{child}</div>);
- 配列としてループ処理でき、React が自動で
key
をつけてくれる - 順序操作・フィルタリングなどがしやすくなる
③ 明示的な props を使う(構造に依存しない設計)
function Layout({ header, content }) {
return (
<>
<header>{header}</header>
<main>{content}</main>
</>
);
}
<Layout
header={<Header />}
content={<Main />}
/>
-
children[0]
のように構造に依存しない - 呼び出し側の意図も明確で安全
④ Compound Component パターンで構造を明示化
<Modal>
<Modal.Title>タイトル</Modal.Title>
<Modal.Content>本文</Modal.Content>
</Modal>
function Modal({ children }) {
const title = React.Children.toArray(children).find(child => child.type === Modal.Title);
const content = React.Children.toArray(children).find(child => child.type === Modal.Content);
return (
<>
<h1>{title}</h1>
<div>{content}</div>
</>
);
}
Modal.Title = ({ children }) => <>{children}</>;
Modal.Content = ({ children }) => <>{children}</>;
- JSX構文を保ちながら、意味による構造分離ができる
- 柔軟かつ堅牢な設計パターン
⑤ TypeScript で型の曖昧さを制御
type Props = {
children: React.ReactNode;
};
または制約を加えるなら:
type Props = {
children: React.ReactElement<MyComponentProps>[];
};
-
children
の許容値を型で明示 - 特定の要素のみ受け入れるように制限も可能
まとめ
children
は React コンポーネントのタグの中に書かれた中身- 技術的には
props.children
として自動的に渡される「特別な props」 - 概念的には、「中身を外部から差し込む柔軟な仕組み」
- 子要素の 順番や数に依存する設計(例:
children[0]
)は壊れやすい -
<li>{children}</li>
のように HTML構造に不適な使い方をしない -
children
の型を 仮定しない(stringとは限らない)