1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactのコンポーネントで「プロパティ」「children」「スロット」のどれを使うべきか

Posted at

おお、同志よ!Reactの深淵なる問い、「包含(Composition)」か「設定(Configuration)」か という聖戦に足を踏み入れたな!😇

Reactにおける children は、我らが神LISPにおける S式(S-Expression)のネスト構造 そのものである。
(parent (child)) という構造を愛する我らにとって、children は極めて自然な表現だ。

しかし、エンジニアとして ロジックの結合度(Coupling)認知負荷(Cognitive Load) を最適化せねばならん。
結論から言えば、「そのコンポーネントが中身を知る必要があるか?」 で決まる。

神の審判(使い分けの基準)を授けよう。


🏛️ 1. children を使うべき時: 「器(Container)」としての責務

コンポーネントが「ただの枠」であり、中身に何が来るか関知しない場合、children が至高である。
これを 制御の反転(Inversion of Control) と呼ぶ。

✅ 適切なケース

  • Card, Modal, Layout, Button
  • 中身がテキストなのか、画像なのか、別のコンポーネントなのか、親が決めるべき場合。
// LISP的思考: (Card (Text "神よ"))
// コンポーネントは「枠」を提供するだけ
const Card = ({ children }: { children: React.ReactNode }) => {
  return <div className="p-4 border shadow">{children}</div>;
};

// 使う側(自由度が高い)
<Card>
  <h1>神への祈り</h1>
  <p>Lisp is God.</p>
</Card>

  • メリット: 結合度が低い。再利用性が高い。
  • デメリット: 子要素の配置場所が「一箇所」に限られる(基本的には)。

🔧 2. props を使うべき時: 「部品(Part)」としての責務

コンポーネントがデータを特定の場所に埋め込んだり、中身の型を厳密に縛りたい場合、props が正義である。

✅ 適切なケース

  • UserAvatar, ProductPrice, specific UI widget
  • 「タイトルはここ」「画像はここ」とレイアウトが厳密に決まっている場合。
// コンポーネントが構造を支配している
type UserCardProps = {
  name: string;
  role: string;
};

const UserCard = ({ name, role }: UserCardProps) => {
  return (
    <div className="border">
      {/* 配置場所はUserCardが決める */}
      <h2 className="font-bold">{name}</h2> 
      <span className="text-gray-500">{role}</span>
    </div>
  );
};

  • メリット: 型安全性(Type Safety)が高い。デザイン崩れを防げる。
  • デメリット: 柔軟性がない。中身を変えるにはコンポーネント自体の修正が必要。

⚔️ 3. 第三の道: 「スロット(Slots)」パターン

ここからがエンジニアの腕の見せ所だ。
「枠ではあるが、穴が複数ある」 場合、children ではなく ReactNode を props で渡す のだ。

✅ 適切なケース

  • Layout (Header / Sidebar / Main), Dialog (Title / Body / Footer)
type LayoutProps = {
  header: React.ReactNode; // 第一のスロット
  sidebar: React.ReactNode; // 第二のスロット
  children: React.ReactNode; // メインコンテンツ
};

const AppLayout = ({ header, sidebar, children }: LayoutProps) => {
  return (
    <div className="grid">
      <header>{header}</header>
      <aside>{sidebar}</aside>
      <main>{children}</main>
    </div>
  );
};

// 使う側:名前付き引数のように渡せる(まさにLispのキーワード引数!)
<AppLayout
  header={<Navbar />}
  sidebar={<Menu />}
>
  <p>Main Content</p>
</AppLayout>


⚖️ 最終審判アルゴリズム

迷った時は、以下のロジックで で決定せよ。

  1. 「そのコンポーネントは、中身の配置を1箇所にまとめたいか?」
  • Yes 👉 children (汎用的なラッパー)
  1. 「そのコンポーネントは、中身のデータ構造を知っている必要があるか?」
  • Yes 👉 props (string, int, object) (専用コンポーネント)
  1. 「そのコンポーネントには、中身を入れる穴が2つ以上あるか?」
  • Yes 👉 props (ReactNode) (スロットパターン)

同志よ、Reactにおける「合成」はLispの精神そのものだ。
「抽象度」 のコントロールなのだ。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?