Reactのchildren propsとは?コンポーネント間の入れ子を理解

React開発で必須のchildren propsの使い方を完全解説。コンポーネント間の入れ子構造から高度なパターンまで、実践的なコード例で理解しましょう。

Learning Next 運営
52 分で読めます

Reactのchildren propsとは?コンポーネント間の入れ子を理解

みなさん、Reactでコンポーネントを作っていて、こんな疑問を持ったことはありませんか?

「他のコンポーネントを包んで使いたいけど、どうやって書くの?」 「childrenって何?どうやって使うの?」

そんな悩みを抱えているのではないでしょうか。

children propsは、Reactの最も重要な概念の一つです。 レイアウトコンポーネント、モーダル、カード、ボタンなど、様々な場面で活用される便利な機能です。

でも心配いりません! 今回は、children propsの基本概念から実践的な使い方まで、わかりやすく解説します。

この記事を読めば、より再利用性の高い、柔軟なコンポーネント設計ができるようになりますよ。 一緒に学んでいきましょう!

children propsとは何か?

children propsの基本概念と、なぜReactで重要なのかを理解しましょう。

基本的な概念

children propsは、コンポーネントのタグの間に配置された内容を受け取るための特別なpropsです。

簡単に言うと、HTMLの入れ子構造をReactコンポーネントでも使えるようにする機能です。

// HTMLの入れ子構造
<div>
<p>これは子要素です</p>
</div>
// Reactコンポーネントの入れ子構造
<Card>
<h2>カードタイトル</h2>
<p>カードの内容です</p>
</Card>

この例では、<h2><p>要素がCardコンポーネントのchildren propsとして渡されます。

実際の使用例

実際にchildren propsを使ったコンポーネントを見てみましょう。

// Cardコンポーネントの定義
function Card({ children }) {
return (
<div className="card">
<div className="card-content">
{children}
</div>
</div>
);
}
// 使用例
function App() {
return (
<div>
<Card>
<h2>お知らせ</h2>
<p>新機能がリリースされました!</p>
<button>詳細を見る</button>
</Card>
<Card>
<h2>イベント情報</h2>
<p>来月にセミナーを開催します</p>
<a href="/events">イベント一覧</a>
</Card>
</div>
);
}

ここでは、Cardコンポーネントが{children}を使って、渡された内容を表示しています。

同じCardコンポーネントでも、中身を変えることで異なる内容を表示できます。

childrenの様々な型

children propsは様々な型の値を受け取ることができます。

function Container({ children }) {
console.log(typeof children); // 内容によって変わる
return <div className="container">{children}</div>;
}
// 文字列
<Container>Hello World</Container>
// 単一の要素
<Container><p>単一の段落</p></Container>
// 複数の要素
<Container>
<h1>タイトル</h1>
<p>内容</p>
</Container>
// 関数
<Container>{(data) => <p>{data}</p>}</Container>
// undefined(子要素がない場合)
<Container></Container>

このように、children propsは非常に柔軟に様々な内容を受け取れます。

childrenの自動的な受け渡し

Reactでは、コンポーネントタグの間に書かれた内容は、自動的にchildren propsとして渡されます。

function Button({ children, onClick, disabled }) {
return (
<button
onClick={onClick}
disabled={disabled}
className="custom-button"
>
{children}
</button>
);
}
// 使用例
<Button onClick={handleClick} disabled={false}>
クリックしてください
</Button>
// 上記は以下と同等
<Button onClick={handleClick} disabled={false} children="クリックしてください" />

つまり、明示的にchildrenを指定しなくても、自動的に渡されるということです。

childrenの利点

children propsを使うことで、以下のような利点があります。

  • 柔軟性: 任意の内容を渡すことができる
  • 再利用性: 同じコンポーネントを異なる内容で使用可能
  • コンポーネントの分離: 見た目と内容を分離できる
  • コンポーネントの階層: 自然な親子関係を表現可能

例えば、以下のようなモーダルコンポーネントを考えてみましょう。

function Modal({ children, isOpen, onClose }) {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal-content">
<button onClick={onClose}>×</button>
{children}
</div>
</div>
);
}
// 様々な内容で使用可能
<Modal isOpen={isLoginModalOpen} onClose={closeLoginModal}>
<h2>ログイン</h2>
<LoginForm />
</Modal>
<Modal isOpen={isConfirmModalOpen} onClose={closeConfirmModal}>
<h2>確認</h2>
<p>本当に削除しますか?</p>
<button onClick={handleDelete}>削除</button>
<button onClick={closeConfirmModal}>キャンセル</button>
</Modal>

同じModalコンポーネントでも、ログイン画面や確認画面など、様々な用途で使えます。

children propsを理解することで、より効率的で保守性の高いコンポーネント設計が可能になります。

基本的な使い方

children propsの基本的な使用方法を、実際のコード例で学びましょう。

シンプルなコンテナコンポーネント

最も基本的な使い方から始めましょう。

// 基本的なコンテナ
function Container({ children }) {
return (
<div className="container">
{children}
</div>
);
}
// 使用例
function App() {
return (
<Container>
<h1>メインタイトル</h1>
<p>ここがメインコンテンツです</p>
</Container>
);
}

このコードでは、Containerコンポーネントが{children}を使って、渡された内容をそのまま表示しています。

シンプルですが、コンテナとしての役割を果たせます。

スタイル付きコンポーネント

children propsとpropsを組み合わせて、より柔軟なコンポーネントを作れます。

function Card({ children, variant = 'default' }) {
const cardClass = `card card-${variant}`;
return (
<div className={cardClass}>
{children}
</div>
);
}
// 使用例
function Dashboard() {
return (
<div>
<Card>
<h2>デフォルトカード</h2>
<p>通常のカードです</p>
</Card>
<Card variant="primary">
<h2>重要なお知らせ</h2>
<p>新機能がリリースされました</p>
</Card>
<Card variant="success">
<h2>成功メッセージ</h2>
<p>操作が正常に完了しました</p>
</Card>
</div>
);
}

この例では、variantpropsでスタイルを変更しながら、childrenで内容を自由に設定できます。

同じコンポーネントでも、見た目と内容を独立して変更できるのがポイントです。

ボタンコンポーネント

ボタンコンポーネントでのchildren propsの使用例を見てみましょう。

function Button({ children, variant = 'primary', size = 'medium', onClick, disabled }) {
const buttonClass = `btn btn-${variant} btn-${size}`;
return (
<button
className={buttonClass}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
);
}
// 使用例
function ActionButtons() {
return (
<div className="button-group">
<Button onClick={() => console.log('保存')}>
保存
</Button>
<Button variant="secondary" onClick={() => console.log('キャンセル')}>
キャンセル
</Button>
<Button variant="danger" size="small" onClick={() => console.log('削除')}>
削除
</Button>
<Button disabled>
無効なボタン
</Button>
</div>
);
}

このコードでは、ボタンの文字列だけでなく、アイコンや複雑な内容もchildrenとして渡すことができます。

リストコンポーネント

リスト形式のコンポーネントでも、children propsが活用できます。

function List({ children, ordered = false }) {
const ListTag = ordered ? 'ol' : 'ul';
return (
<ListTag className="custom-list">
{children}
</ListTag>
);
}
function ListItem({ children }) {
return (
<li className="list-item">
{children}
</li>
);
}
// 使用例
function TodoList() {
return (
<div>
<h2>やることリスト</h2>
<List>
<ListItem>
<input type="checkbox" />
<span>買い物に行く</span>
</ListItem>
<ListItem>
<input type="checkbox" />
<span>レポートを書く</span>
</ListItem>
<ListItem>
<input type="checkbox" />
<span>会議に参加する</span>
</ListItem>
</List>
<h2>手順</h2>
<List ordered>
<ListItem>アカウント作成</ListItem>
<ListItem>プロフィール設定</ListItem>
<ListItem>コンテンツ投稿</ListItem>
</List>
</div>
);
}

ListListItemコンポーネントを組み合わせて、構造化されたリストを作成できます。

各リストアイテムの内容は、childrenとして自由に設定できます。

セクションコンポーネント

ページのセクションを表現するコンポーネントの例です。

function Section({ children, title, subtitle }) {
return (
<section className="section">
{title && <h2 className="section-title">{title}</h2>}
{subtitle && <p className="section-subtitle">{subtitle}</p>}
<div className="section-content">
{children}
</div>
</section>
);
}
// 使用例
function AboutPage() {
return (
<div>
<Section title="会社概要" subtitle="私たちについて">
<p>弊社は2020年に設立された新しい会社です。</p>
<p>最新の技術を使ってサービスを提供しています。</p>
</Section>
<Section title="サービス">
<div className="services-grid">
<div className="service-item">
<h3>Webアプリ開発</h3>
<p>モダンな技術を使用した開発</p>
</div>
<div className="service-item">
<h3>コンサルティング</h3>
<p>技術的な課題解決をサポート</p>
</div>
</div>
</Section>
<Section title="お問い合わせ">
<form>
<input type="text" placeholder="お名前" />
<input type="email" placeholder="メールアドレス" />
<textarea placeholder="メッセージ"></textarea>
<button type="submit">送信</button>
</form>
</Section>
</div>
);
}

このコードでは、Sectionコンポーネントがタイトルとサブタイトルを管理し、childrenで実際の内容を表示しています。

条件付きレンダリング

children propsを使った条件付きレンダリングも便利です。

function ConditionalWrapper({ children, condition, fallback = null }) {
if (!condition) {
return fallback;
}
return <div className="conditional-wrapper">{children}</div>;
}
// 使用例
function UserProfile({ user }) {
return (
<div>
<h1>プロフィール</h1>
<ConditionalWrapper
condition={user.isVerified}
fallback={<p>アカウントが未認証です</p>}
>
<div className="verified-content">
<p>認証済みユーザー: {user.name}</p>
<p>メール: {user.email}</p>
</div>
</ConditionalWrapper>
<ConditionalWrapper condition={user.isPremium}>
<div className="premium-features">
<h2>プレミアム機能</h2>
<p>プレミアムユーザー限定の機能です</p>
</div>
</ConditionalWrapper>
</div>
);
}

この例では、条件に応じてchildrenを表示したり、フォールバック内容を表示したりできます。

これらの基本的な使い方を理解することで、children propsの力を活用したコンポーネント設計ができるようになります。

高度な使い方

children propsを使った高度なパターンと実践的なテクニックを学びましょう。

React.Children APIの活用

Reactは、children propsを操作するためのReact.Children APIを提供しています。

import React from 'react';
function TabContainer({ children, activeTab, onTabChange }) {
// children の数を取得
const childCount = React.Children.count(children);
// children を配列として処理
const childArray = React.Children.toArray(children);
return (
<div className="tab-container">
<div className="tab-nav">
{React.Children.map(children, (child, index) => (
<button
key={index}
className={`tab-button ${activeTab === index ? 'active' : ''}`}
onClick={() => onTabChange(index)}
>
{child.props.label}
</button>
))}
</div>
<div className="tab-content">
{childArray[activeTab]}
</div>
</div>
);
}
function Tab({ children, label }) {
return <div className="tab-panel">{children}</div>;
}

このコードでは、React.Children.mapを使って各タブのボタンを作成しています。

React.Children.toArrayで配列に変換し、アクティブなタブを表示しています。

使用例を見てみましょう。

// 使用例
function MyTabs() {
const [activeTab, setActiveTab] = useState(0);
return (
<TabContainer activeTab={activeTab} onTabChange={setActiveTab}>
<Tab label="プロフィール">
<h2>プロフィール情報</h2>
<p>名前: 田中太郎</p>
<p>年齢: 30歳</p>
</Tab>
<Tab label="設定">
<h2>設定</h2>
<label>
<input type="checkbox" />
通知を受け取る
</label>
</Tab>
<Tab label="ヘルプ">
<h2>ヘルプ</h2>
<p>よくある質問はこちら</p>
</Tab>
</TabContainer>
);
}

このパターンを使うことで、動的なタブシステムを作成できます。

Render Props パターン

children propsを関数として使用するパターンです。

function DataProvider({ children, url }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, [url]);
// children を関数として呼び出し
return children({ data, loading, error });
}
// 使用例
function UserList() {
return (
<DataProvider url="/api/users">
{({ data, loading, error }) => {
if (loading) return <div>読み込み中...</div>;
if (error) return <div>エラー: {error.message}</div>;
if (!data) return <div>データがありません</div>;
return (
<ul>
{data.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}}
</DataProvider>
);
}

このパターンでは、childrenを関数として定義し、データを引数として渡しています。

データの状態に応じて、適切な表示を行うことができます。

複雑なレイアウトコンポーネント

複数の領域を持つレイアウトコンポーネントの例です。

function Layout({ children, sidebar, header, footer }) {
return (
<div className="layout">
{header && (
<header className="layout-header">
{header}
</header>
)}
<div className="layout-main">
{sidebar && (
<aside className="layout-sidebar">
{sidebar}
</aside>
)}
<main className="layout-content">
{children}
</main>
</div>
{footer && (
<footer className="layout-footer">
{footer}
</footer>
)}
</div>
);
}
// 使用例
function App() {
return (
<Layout
header={
<nav>
<h1>My App</h1>
<ul>
<li>ホーム</li>
<li>プロフィール</li>
<li>設定</li>
</ul>
</nav>
}
sidebar={
<div>
<h2>サイドバー</h2>
<ul>
<li>リンク1</li>
<li>リンク2</li>
<li>リンク3</li>
</ul>
</div>
}
footer={<p>&copy; 2025 My App</p>}
>
<h1>メインコンテンツ</h1>
<p>ここがメインエリアです</p>
</Layout>
);
}

このコードでは、複数の領域(header、sidebar、footer)を持つレイアウトを作成しています。

各領域はpropsとして渡し、メインコンテンツはchildrenとして扱います。

条件付きコンポーネントラッパー

条件に応じてプロバイダーを適用するパターンです。

function ConditionalProvider({ children, condition, provider: Provider, ...providerProps }) {
if (condition && Provider) {
return <Provider {...providerProps}>{children}</Provider>;
}
return children;
}
// 使用例
function AppWithConditionalProvider() {
const [isDarkMode, setIsDarkMode] = useState(false);
return (
<ConditionalProvider
condition={isDarkMode}
provider={ThemeProvider}
theme="dark"
>
<div className="app">
<button onClick={() => setIsDarkMode(!isDarkMode)}>
{isDarkMode ? 'ライトモード' : 'ダークモード'}
</button>
<MainContent />
</div>
</ConditionalProvider>
);
}

このパターンでは、条件に応じてプロバイダーを適用したり、そのままchildrenを返したりできます。

高度なフォームコンポーネント

フォームフィールドを構造化するコンポーネントの例です。

function FormField({ children, label, error, required }) {
return (
<div className="form-field">
<label className="form-label">
{label}
{required && <span className="required">*</span>}
</label>
<div className="form-input">
{children}
</div>
{error && (
<div className="form-error">
{error}
</div>
)}
</div>
);
}
function FormSection({ children, title, subtitle }) {
return (
<div className="form-section">
{title && <h2 className="section-title">{title}</h2>}
{subtitle && <p className="section-subtitle">{subtitle}</p>}
<div className="section-fields">
{children}
</div>
</div>
);
}

これらのコンポーネントを組み合わせて、構造化されたフォームを作成できます。

// 使用例
function RegistrationForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
age: '',
bio: ''
});
const [errors, setErrors] = useState({});
return (
<form className="registration-form">
<FormSection
title="基本情報"
subtitle="必須項目を入力してください"
>
<FormField label="名前" required error={errors.name}>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({...formData, name: e.target.value})}
placeholder="田中太郎"
/>
</FormField>
<FormField label="メールアドレス" required error={errors.email}>
<input
type="email"
value={formData.email}
onChange={(e) => setFormData({...formData, email: e.target.value})}
placeholder="example@email.com"
/>
</FormField>
<FormField label="年齢" error={errors.age}>
<input
type="number"
value={formData.age}
onChange={(e) => setFormData({...formData, age: e.target.value})}
min="0"
max="120"
/>
</FormField>
</FormSection>
<FormSection
title="プロフィール"
subtitle="オプション項目です"
>
<FormField label="自己紹介">
<textarea
value={formData.bio}
onChange={(e) => setFormData({...formData, bio: e.target.value})}
placeholder="自己紹介を書いてください"
rows="4"
/>
</FormField>
</FormSection>
<button type="submit">登録</button>
</form>
);
}

このパターンでは、フォームの構造を明確にし、各フィールドの見た目を統一できます。

これらの高度なパターンを理解することで、より柔軟で再利用性の高いコンポーネント設計が可能になります。

実践的な活用例

実際のアプリケーション開発で役立つ、children propsの実践的な活用例を紹介します。

モーダルコンポーネント

モーダルダイアログは、children propsの代表的な活用例です。

function Modal({ children, isOpen, onClose, title, size = 'medium' }) {
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
return () => {
document.body.style.overflow = 'unset';
};
}, [isOpen]);
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div
className={`modal-content modal-${size}`}
onClick={(e) => e.stopPropagation()}
>
<div className="modal-header">
{title && <h2>{title}</h2>}
<button className="modal-close" onClick={onClose}>
×
</button>
</div>
<div className="modal-body">
{children}
</div>
</div>
</div>
);
}

このモーダルコンポーネントは、様々な内容を表示できる汎用的なコンポーネントです。

childrenを使うことで、ログイン画面、確認画面、画像表示など、様々な用途に対応できます。

// 使用例
function App() {
const [showLoginModal, setShowLoginModal] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const [showImageModal, setShowImageModal] = useState(false);
return (
<div>
<button onClick={() => setShowLoginModal(true)}>
ログイン
</button>
<button onClick={() => setShowConfirmModal(true)}>
削除
</button>
<button onClick={() => setShowImageModal(true)}>
画像を表示
</button>
{/* ログインモーダル */}
<Modal
isOpen={showLoginModal}
onClose={() => setShowLoginModal(false)}
title="ログイン"
>
<form>
<input type="email" placeholder="メールアドレス" />
<input type="password" placeholder="パスワード" />
<button type="submit">ログイン</button>
</form>
</Modal>
{/* 確認モーダル */}
<Modal
isOpen={showConfirmModal}
onClose={() => setShowConfirmModal(false)}
title="確認"
size="small"
>
<p>本当に削除しますか?</p>
<div className="modal-actions">
<button onClick={() => setShowConfirmModal(false)}>
キャンセル
</button>
<button className="danger">
削除
</button>
</div>
</Modal>
{/* 画像モーダル */}
<Modal
isOpen={showImageModal}
onClose={() => setShowImageModal(false)}
size="large"
>
<img
src="/sample-image.jpg"
alt="サンプル画像"
style={{ width: '100%', height: 'auto' }}
/>
</Modal>
</div>
);
}

同じModalコンポーネントでも、childrenの内容を変えることで、全く異なる機能を実現できます。

ドロップダウンメニュー

ドロップダウンメニューも、children propsを活用した実用的な例です。

function Dropdown({ children, trigger, position = 'bottom-left' }) {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
return (
<div className="dropdown" ref={dropdownRef}>
<div
className="dropdown-trigger"
onClick={() => setIsOpen(!isOpen)}
>
{trigger}
</div>
{isOpen && (
<div className={`dropdown-content dropdown-${position}`}>
{children}
</div>
)}
</div>
);
}
function DropdownItem({ children, onClick }) {
return (
<div className="dropdown-item" onClick={onClick}>
{children}
</div>
);
}

このドロップダウンコンポーネントは、トリガー要素と中身を自由に設定できます。

// 使用例
function NavigationBar() {
const [user, setUser] = useState({ name: '田中太郎', role: 'admin' });
return (
<nav className="navbar">
<div className="nav-brand">My App</div>
<div className="nav-items">
<Dropdown
trigger={
<button className="nav-button">
メニュー ▼
</button>
}
>
<DropdownItem onClick={() => console.log('ホーム')}>
🏠 ホーム
</DropdownItem>
<DropdownItem onClick={() => console.log('プロフィール')}>
👤 プロフィール
</DropdownItem>
<DropdownItem onClick={() => console.log('設定')}>
⚙️ 設定
</DropdownItem>
</Dropdown>
<Dropdown
trigger={
<div className="user-avatar">
{user.name.charAt(0)}
</div>
}
position="bottom-right"
>
<DropdownItem>
<strong>{user.name}</strong>
<br />
<small>{user.role}</small>
</DropdownItem>
<hr />
<DropdownItem onClick={() => console.log('プロフィール編集')}>
プロフィール編集
</DropdownItem>
<DropdownItem onClick={() => console.log('ログアウト')}>
ログアウト
</DropdownItem>
</Dropdown>
</div>
</nav>
);
}

このパターンでは、同じDropdownコンポーネントでも、トリガーとメニュー内容を変えることで、全く異なる機能を実現できます。

アコーディオンコンポーネント

アコーディオンは、FAQ やメニューでよく使われるUIパターンです。

function Accordion({ children, allowMultiple = false }) {
const [openItems, setOpenItems] = useState(new Set());
const toggleItem = (index) => {
setOpenItems(prev => {
const newSet = new Set(prev);
if (newSet.has(index)) {
newSet.delete(index);
} else {
if (!allowMultiple) {
newSet.clear();
}
newSet.add(index);
}
return newSet;
});
};
return (
<div className="accordion">
{React.Children.map(children, (child, index) => (
React.cloneElement(child, {
isOpen: openItems.has(index),
onToggle: () => toggleItem(index)
})
))}
</div>
);
}
function AccordionItem({ children, title, isOpen, onToggle }) {
return (
<div className="accordion-item">
<div
className={`accordion-header ${isOpen ? 'open' : ''}`}
onClick={onToggle}
>
<span>{title}</span>
<span className="accordion-icon">
{isOpen ? '−' : '+'}
</span>
</div>
{isOpen && (
<div className="accordion-content">
{children}
</div>
)}
</div>
);
}

このアコーディオンコンポーネントは、React.cloneElementを使って子コンポーネントにpropsを渡しています。

// 使用例
function FAQSection() {
return (
<div className="faq-section">
<h1>よくある質問</h1>
<Accordion allowMultiple>
<AccordionItem title="アカウントの作成方法は?">
<p>画面右上の「新規登録」ボタンをクリックして、必要な情報を入力してください。</p>
<p>メールアドレスの認証が完了すると、アカウントが有効になります。</p>
</AccordionItem>
<AccordionItem title="パスワードを忘れました">
<p>ログイン画面の「パスワードを忘れた方」リンクをクリックしてください。</p>
<p>登録済みのメールアドレスに、パスワードリセットのリンクが送信されます。</p>
</AccordionItem>
<AccordionItem title="料金プランの変更方法は?">
<p>アカウント設定の「料金プラン」セクションから変更できます。</p>
<p>プランの変更は即座に反映されます。</p>
</AccordionItem>
<AccordionItem title="データのバックアップは?">
<p>データは自動的にバックアップされます。</p>
<p>手動でのエクスポートも可能です。</p>
</AccordionItem>
</Accordion>
</div>
);
}

このパターンでは、アコーディオンアイテムの内容をchildrenで自由に設定できます。

カードベースのレイアウト

カードベースのレイアウトは、ダッシュボードやカタログでよく使われます。

function CardGrid({ children, columns = 3, gap = '16px' }) {
const gridStyle = {
display: 'grid',
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: gap
};
return (
<div className="card-grid" style={gridStyle}>
{children}
</div>
);
}
function Card({ children, variant = 'default', clickable = false, onClick }) {
const cardClass = `card card-${variant} ${clickable ? 'clickable' : ''}`;
return (
<div className={cardClass} onClick={clickable ? onClick : undefined}>
{children}
</div>
);
}
function CardHeader({ children }) {
return <div className="card-header">{children}</div>;
}
function CardBody({ children }) {
return <div className="card-body">{children}</div>;
}
function CardFooter({ children }) {
return <div className="card-footer">{children}</div>;
}

これらのコンポーネントを組み合わせて、柔軟なカードレイアウトを作成できます。

// 使用例
function Dashboard() {
const stats = [
{ title: '総売上', value: '¥1,234,567', trend: '+12%' },
{ title: '新規顧客', value: '456', trend: '+8%' },
{ title: '注文数', value: '789', trend: '+15%' },
{ title: '平均単価', value: '¥12,345', trend: '+3%' }
];
return (
<div className="dashboard">
<h1>ダッシュボード</h1>
<CardGrid columns={4}>
{stats.map((stat, index) => (
<Card key={index} variant="stat">
<CardHeader>
<h3>{stat.title}</h3>
</CardHeader>
<CardBody>
<p className="stat-value">{stat.value}</p>
<p className="stat-trend">{stat.trend}</p>
</CardBody>
</Card>
))}
</CardGrid>
<CardGrid columns={2}>
<Card>
<CardHeader>
<h2>最近の注文</h2>
</CardHeader>
<CardBody>
<ul>
<li>注文 #001 - ¥15,000</li>
<li>注文 #002 - ¥8,500</li>
<li>注文 #003 - ¥22,000</li>
</ul>
</CardBody>
<CardFooter>
<button>全ての注文を見る</button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<h2>アクティビティ</h2>
</CardHeader>
<CardBody>
<ul>
<li>新規顧客が登録しました</li>
<li>商品が追加されました</li>
<li>レビューが投稿されました</li>
</ul>
</CardBody>
<CardFooter>
<button>全てのアクティビティを見る</button>
</CardFooter>
</Card>
</CardGrid>
</div>
);
}

このパターンでは、カードの構造を統一しながら、内容を自由に設定できます。

これらの実践的な例により、children propsの活用方法を具体的に理解できます。

まとめ

この記事では、Reactのchildren propsについて詳しく解説しました。

重要なポイント

1. 基本概念

  • children propsは、コンポーネントタグの間に配置された内容を受け取る特別なprops
  • 文字列、要素、関数など、様々な型の値を受け取れる
  • 自動的にコンポーネントに渡される

2. 基本的な使い方

  • コンテナコンポーネント、ボタン、カードなどの汎用コンポーネントに活用
  • 再利用性の高いコンポーネント設計が可能
  • 柔軟な内容の表示ができる

3. 高度な使い方

  • React.Children API(map, count, toArray等)を使った操作
  • Render Props パターンで関数としてのchildren活用
  • 条件付きレンダリングや動的コンポーネント生成

4. 実践的な活用例

  • モーダル、ドロップダウン、アコーディオンなどのUIコンポーネント
  • レイアウトコンポーネントでの構造化
  • カードベースのUIでの柔軟な表示

children propsの利点

主な利点をまとめます。

  • 再利用性: 同じコンポーネントを異なる内容で使用可能
  • 柔軟性: 任意の要素や内容を渡すことができる
  • 分離: 見た目とコンテンツを分離できる
  • 階層構造: 自然な親子関係を表現

使用時の注意点

children propsを使う際の注意点をおさらいします。

// 良い例:型チェック
function Container({ children }) {
return <div className="container">{children}</div>;
}
// 良い例:条件付きレンダリング
function OptionalContainer({ children, show = true }) {
return show ? <div className="container">{children}</div> : null;
}
// 注意:children が関数の場合
function RenderPropComponent({ children }) {
const data = useData();
return typeof children === 'function' ? children(data) : children;
}

型チェックや条件付きレンダリングを適切に行うことが重要です。

今後の学習

children propsを理解したら、次のステップに進みましょう。

  • React Context: グローバルな状態管理
  • Custom Hooks: ロジックの再利用
  • Higher-Order Components: コンポーネントの拡張
  • Compound Components: より複雑なコンポーネント設計

実践への応用

学習したパターンを組み合わせて、実際のアプリケーションに活用してみましょう。

// 学習したパターンを組み合わせた例
function App() {
return (
<Layout
header={<Header />}
sidebar={<Sidebar />}
>
<Modal isOpen={showModal} onClose={closeModal}>
<Accordion>
<AccordionItem title="セクション1">
<Card>
<CardHeader>タイトル</CardHeader>
<CardBody>内容</CardBody>
</Card>
</AccordionItem>
</Accordion>
</Modal>
</Layout>
);
}

このように、様々なパターンを組み合わせることで、複雑で柔軟なUIを構築できます。

children propsは、Reactの最も強力で柔軟な機能の一つです。

この知識を活用して、再利用性が高く、保守性に優れたコンポーネントを設計してください。 きっと、より良いReactアプリケーションが作れるようになりますよ!

ぜひ、実際のプロジェクトで試してみてください。 children propsをマスターして、React開発スキルを向上させましょう!

関連記事