ReactのPropsとは?初心者から上級者まで徹底解説【2025年最新動向:RSC、TypeScript対応】

Reactアプリケーション開発の核心には、常に「Props」が存在します。Props(プロップス)は、Reactのコンポーネントベース・アーキテクチャを支える最も基本的かつ強力な概念です。その役割は、Reactの誕生から今日のReact 19におけるReact Server Components(RSC)の登場に至るまで、進化を続けています。

本レポートでは、ReactのPropsに関する包括的な解説を、海外の技術文献や公式ドキュメントに基づき、非エンジニア向けの基礎から開発者向けの高度なパターン、最新の技術動向まで、実例を交えて詳細に解説します。

目次

セクション1:React Propsの基本原則 — 非エンジニアにもわかる核心

このセクションでは、技術的な背景を持たないプロジェクトマネージャーやデザイナーにも伝わるよう、Propsの基本的な概念とその重要性を解説します。

Propsとは何か?コンポーネントに渡す「指示書」

ReactのUIは、「レゴブロック」の集まりとして考えると理解しやすいです 1。一つひとつのUI部品(ボタン、フォーム、ヘッダーなど)が「コンポーネント」と呼ばれる独立したブロックです。

**Props(Propertiesの略)とは、これらのコンポーネント(レゴブロック)を組み立てる際に渡す「指示書」や「設定値」**のことです 2

例えば、<Button>というボタンコンポーネントがあったとします。このコンポーネントを再利用可能な部品にするためには、ボタンを配置する場所によって、その振る舞いや見た目をカスタマイズできる必要があります。

  • 「このボタンの色は青にしてほしい」(例:color=”blue”)
  • 「表示する文字は『送信』にしてほしい」(例:text=”送信”) 4
  • 「クリックされたら、この動作(例:データを送信)を実行してほしい」(例:onClick={handleSubmit}) 5

これら一つひとつの具体的な指示がPropsです。

技術的に言えば、Propsは親コンポーネントから子コンポーネントへデータを渡すための主要な手段であり 2、コンポーネントの再利用性を高めるための核となる仕組みです 7

Propsの最大の特徴:データは「読み取り専用(Immutable)」

Propsを理解する上で最も重要なルールが一つあります。それは、**「Propsは読み取り専用である」**ということです 2

これは、先ほどの「指示書」の例えで言うと、「指示書を受け取った側(子コンポーネント)は、その指示書を勝手に書き換えてはならない」というルールです。

もし「青いボタン」として作られたボタンが、自分自身の判断で「赤いボタン」に色を変えてしまったら、アプリケーション全体のUIの秩序が失われ、不具合の原因となります。データは必ず「親」から「子」へと一方向に流れます 2。これを**「単方向データフロー(Unidirectional Data Flow)」**と呼びます。

この「Propsは不変(Immutable)である」という制約は、単なる機能ではなく、Reactの「単方向データフロー」という設計思想を強制するための仕組みです。もしPropsが可変であれば、子が親の状態を意図せず変更できてしまい、データフローが双方向になり、アプリケーションの挙動は予測不可能になります。Propsの不変性こそが、Reactアプリケーションの予測可能性とデバッグの容易性を支える根源です。

Props vs State:Reactにおける「渡されるデータ」と「持つデータ」

Reactの初学者が最も混乱するポイントが、PropsとStateの違いです 10。この二つは、Reactコンポーネントが扱う「データ」という点では同じですが、その出所と役割が根本的に異なります。

  • Props(渡されるデータ): コンポーネントの**「外」から**渡される設定値です。これは、関数の世界における「引数(arguments)」によく例えられます 11。Propsは親コンポーネントが所有しており、子コンポーネントはそれを受け取って読み取ることしかできません 12
  • State(持つデータ): コンポーネントが**「内」で**独自に管理する「記憶」です。これは、コンポーネントの「メモリ」に例えられます 11。例えば、フォームに入力中のテキスト、トグルスイッチのON/OFF状態、マウスが乗っているかどうかの状態(isHovered)など、時間経過やユーザーの操作によって変化する動的なデータがStateです 11。Stateは可変(Mutable)であり、コンポーネント自身が専用の関数(setState)を使って変更できます 8

PropsとStateの区別は、コンポーネントを設計する上での最初のアーキテクチャ設計です。最も一般的で基本的なパターンは、「親コンポーネントがStateとしてデータを持ち、そのデータを子コンポーネントにPropsとして渡す」というものです 11。このデータの分類(これはPropsか? Stateか?)を誤ることが、Reactのバグの主な原因となります。

【テーブル1:PropsとStateの機能比較表】

特徴Props (プロップス)State (ステート)
データの役割外部からの設定値(関数の引数) 11内部の記憶(ローカル変数) 11
可変性不変(Immutable / 読み取り専用) 8可変(Mutable / 読み書き可能) 8
所有者親コンポーネント 12コンポーネント自身 12
データの流れ親から子への一方通行 2コンポーネント内で完結 9
主な用途コンポーネントのカスタマイズ、再利用 6動的なUIの変更、インタラクションの管理 8
再利用性への影響高める(Propsが多いほど汎用的に) 8影響しない(Stateは自己完結) 8

セクション2:実践:Propsの基本的な使い方と主要パターン

このセクションでは、開発者向けに具体的なコード例を交えながら、日常的に使われるPropsのパターンを解説します。

Propsの渡し方と受け取り方(実例コード)

Propsの受け渡しは非常に直感的です。

1. 親コンポーネント(渡す側)

親コンポーネントは、JSXタグに対し、HTMLの属性(attributes)を記述するのと同じ構文でPropsを渡します 4。

JavaScript

// 親コンポーネント (App.js)
import Welcome from ‘./Welcome’;

function App() {
  // ‘name’ というPropsに “Sara” という文字列を渡す
  return (
    <div>
      <Welcome name=”Sara” />
      <Welcome name=”Cahal” />
    </div>
  );
}

2. 子コンポーネント(受け取る側)

子コンポーネントは、関数の第一引数としてPropsを受け取ります。

方法1:propsオブジェクトとして受け取る

Propsは、渡されたすべてのデータ(この場合は{name: ‘Sara’})を含む単一のオブジェクトとして渡されます 3。

JavaScript

// 子コンポーネント (Welcome.js)
function Welcome(props) {
  // props オブジェクトの name プロパティにアクセス
  return <h1>Hello, {props.name}</h1>; //
}

方法2:分割代入(Destructuring)で受け取る(推奨)

現代のReact開発では、ES6の分割代入構文を使い、propsオブジェクトから必要なプロパティだけを直接取り出す方法が主流です。これにより、コードがクリーンになり、どのPropsが使われているかが一目瞭然になります 4。

JavaScript

// 子コンポーネント (Welcome.js)
// 引数の時点で { name } と記述して取り出す
function Welcome({ name }) {
  return <h1>Hello, {name}</h1>;
}

特別なProps:「children」が実現するコンポーネント合成

Propsの中でも一つだけ特別な名前を持つものがprops.childrenです。これは、コンポーネントの開始タグ(<Tag>)と終了タグ(</Tag>)の間にネストされたすべての内容(JSX)を受け取るための、予約されたPropsです 14

childrenを使うと、「汎用的な箱」コンポーネントを作ることができます 16。例えば、<Card>という枠組みコンポーネントを作り、その「中身」は<Card>を使う側が自由に定義できるようにしたい場合に使います 15

JavaScript

// 親コンポーネント (App.js)
// <Card> と </Card> の間にある h1 と p が Card の ‘children’ になる
<Card>
  <h1>今週のトピック</h1>
  <p>React Server Componentsについて。</p>
</Card>

// 子コンポーネント (Card.js)
function Card({ children }) {
  // 受け取った ‘children’ (h1 と p) を好きな場所に配置する
  return (
    <div className=”card”>
      <div className=”card-content”>
        {children}
      </div>
    </div>
  );
}

この<Card>{…}</Card>のようにコンポーネントを組み合わせるパターンは「コンポーネント合成(Composition)」と呼ばれ、Propsを何層にもわたって深く掘り下げて渡す「Prop Drilling」問題(セクション4で詳述)の最もシンプルかつ強力な解決策となります 18

知っておくべき高度なパターン

1. Propsとして関数を渡す

Propsは読み取り専用ですが、子が親のデータを変更したい場合はどうすればよいでしょうか?

答えは、「親が、自身のStateを変更する関数を、Propsとして子に渡す」ことです 5。

JavaScript

// 親コンポーネント
function Counter() {
  const [count, setCount] = React.useState(0);

  // 1. 親が State を変更する関数を定義する
  function handleIncrement() {
    setCount(count + 1);
  }

  // 2. ‘onButtonClick’ というProps名で、その関数を子に渡す
  return (
    <div>
      <Display count={count} />
      <MyButton onButtonClick={handleIncrement} />
    </div>
  );
}

// 子コンポーネント
function MyButton({ onButtonClick }) {
  // 3. 子は渡された関数を onClick イベントで呼び出す
  return <button onClick={onButtonClick}>+1</button>;
}

function Display({ count }) {
  return <p>Count: {count}</p>;
}

2. スプレッド構文({…props})

受け取ったPropsを、変更せずにそのまま別のコンポーネントやHTML要素にすべて渡したい場合、スプレッド構文({…props})が非常に便利です 4

JavaScript

// HTMLの <button> をラップするカスタムボタン
function CustomButton(props) {
  // ‘className’ や ‘onClick’, ‘aria-label’ など、
  // CustomButton が受け取ったすべてのPropsを
  // 内部の <button> 要素に一括で展開(スプレッド)する
  return <button {…props}>{props.children}</button>;
}

// 使う側
<CustomButton onClick={() => alert(‘Clicked!’)} className=”primary”>
  Click Me
</CustomButton>

props.childrenとスプレッド構文{…props}は、一見無関係に見えますが、「コンポーネントの抽象化」という共通の目的を持っています。childrenはコンポーネントが「何を含むか」を抽象化し、スプレッド構文は「どのように設定されるか」(aria-labelやdata-testidなど、コンポーネントが直接関知しない未知の属性を含む)を抽象化します。

ただし、このスプレッド構文の利便性にはリスクも伴います。特にHTML要素に直接{…props}を使うと、意図しないHTML属性や、場合によっては悪意のある属性(例:dangerouslySetInnerHTMLなど)がDOMに注入される危険性があると指摘されています 21。これは、コンポーネントの内部実装(例:<div>を使っている)が外部に漏れる「leaky abstraction(漏洩した抽象化)」を引き起こす可能性があります。

3. Propsのデフォルト値

Propsが親から渡されなかった場合の初期値を設定できます。

  • (旧)defaultProps: かつてはdefaultPropsという静的プロパティが使われていました 22
  • (新)ES6デフォルト引数(推奨): 現代の関数コンポーネントでは、分割代入と同時にデフォルト値を指定するのが最もクリーンな方法です 4

JavaScript

// ‘size’ が渡されない場合、デフォルトで 100 が使われる
function Avatar({ person, size = 100 }) {
  //…
}

defaultProps 22 からES6デフォルト引数 24 への移行は、ReactがReact固有の機能から標準のJavaScript機能へと移行している大きなトレンドの一部です 25。これにより、Reactコードの学習コストが下がり、JavaScript開発者にとってより親しみやすいものになっています。

セクション3:Propsとパフォーマンス — React.memoによる最適化

Propsは、Reactアプリケーションのパフォーマンス、特に「再レンダリング」の最適化と密接に関連しています。

なぜ最適化が必要か? 親が再レンダリングされると子も再レンダリングされる

Reactのデフォルトの動作では、親コンポーネントが(自身のState更新などで)再レンダリングされると、その親が呼び出しているすべての子コンポーネントも、Propsが変更されているか否かに関わらず、再レンダリングされます 26

これが大規模なアプリケーションになると、不要な再レンダリングが積み重なり、パフォーマンスの低下を引き起こします。

React.memoとは? Propsの変更を監視する

React.memoは、この不要な再レンダリングを防ぐためのツールです。これは関数コンポーネントをラップする「高階コンポーネント(HOC)」です 27

React.memoでラップされたコンポーネントは、親が再レンダリングされても、自身のPropsが「前回と変わっていない」と判断した場合、再レンダリング処理をスキップします 29

JavaScript

const MyComponent = ({ data }) => {
  //…重い計算処理…
  console.log(‘Rendering MyComponent’);
  return <div>{data.name}</div>;
};

// MyComponentをReact.memoでラップする
// これにより、’data’ propが変更されない限り再レンダリングされなくなる
export default React.memo(MyComponent); //

memoが機能しない時:浅い比較(Shallow Comparison)の罠

React.memoは万能ではありません。なぜなら、デフォルトではPropsが「前回と変わっていないか」を**「浅い比較(Shallow Comparison)」**で判断するためです 30

  • 浅い比較:
  • 文字列や数値などのプリミティブ値(例:prop=”text”)は、値が同じであれば「変更なし」と正しく判断できます。
  • オブジェクト、配列、関数などの参照型(例:prop={{}}, prop={}, prop={() => {}})は、中身が同じでも、レンダリングの度に新しい参照(メモリ上のアドレス)が作られるため、常に「変更あり」と誤って判断されます 31

アンチパターン(memoが無力化される例):

JavaScript

function Parent() {
  const [count, setCount] = useState(0);

  // ‘user’ オブジェクトと ‘handleClick’ 関数は
  // Parentが再レンダリングされるたびに「再定義」される
  const user = { name: ‘Alice’ };
  const handleClick = () => console.log(‘click’);

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>Re-render Parent</button>
     
      {/*
        userとhandleClickは毎回新しい参照になるため、
        MemoizedChild は ‘Propsが変わった’ と判断し、再レンダリングされてしまう
      */}
      <MemoizedChild user={user} onClick={handleClick} />
    </div>
  );
}

このパフォーマンス最適化の難しさは、React.memoの浅い比較 30 という動作と、JavaScriptの参照型の特性 31 の組み合わせが根本原因です。

この問題を解決し、React.memoを正しく機能させるには、親コンポーネント側でuseMemoフック(オブジェクトや配列の参照をメモ化)とuseCallbackフック(関数の参照をメモ化)を使い、Propsとして渡す参照自体を固定化する必要があります。

memoの乱用を避ける:最適化が逆効果になる時

React.memoは「最適化」であると同時に、「Propsを比較する」という新たな「コスト」を導入します 32。そのため、むやみに使用すると逆にパフォーマンスを低下させる可能性があります。

React.memoは万能薬ではなく、特定の条件下でのみ有効な処方箋です 27

  • memoが有効なケース(以下の3つをすべて満たす場合) 27
  1. そのコンポーネントが頻繁に再レンダリングされる。
  2. かつ、同じPropsで再レンダリングされることが多い。
  3. かつ、そのコンポーネントのレンダリング処理自体が重い(例:複雑な計算、多くの要素を描画)。
  • memoが不要(または有害)なケース
  1. Propsがレンダリングの度にほぼ毎回変わるコンポーネント(比較するだけ無駄)。
  2. レンダリングが非常に軽量なコンポーネント(比較コストのほうが高くつく) 32

開発者はまずmemoなしで構築し、React DevToolsのプロファイラ機能 30 を使って実際のパフォーマンスボトルネックを特定し、上記の基準に合致した場合にのみmemoを適用すべきです。「早すぎる最適化」は避ける必要があります 27

セクション4:深刻な問題「プロップバケツリレー」とその解決策

アプリケーションのコンポーネント階層が深くなると、Propsの受け渡しが設計上の大きな問題となります。それが「プロップバケツリレー(Prop Drilling)」です。

プロップバケツリレー(Prop Drilling)とは?

あるデータ(例:ログイン中のuserオブジェクト)を、コンポーネントツリーの最上部(例:App)から、ツリーの奥深く(例:Avatar)まで渡したい場合に発生します 35

App → Page → Sidebar → Profile → Avatar

このとき、途中のPage、Sidebar、Profileといったコンポーネントは、userデータを全く使う必要がないにもかかわらず、Avatarコンポーネントにデータを届けるためだけに、Propsを受け取り、それをそのまま子コンポーネントに渡すためだけのコードを書く必要があります 37

この「バケツリレー」のようなデータの受け渡しは、以下の深刻な問題を引き起こします。

  • 保守性の低下: コードが冗長になります 40
  • リファクタリングの困難: 途中のコンポーネントのProps定義を変更するだけでも、その上下すべてのコンポーネントに影響が及びます 39
  • 密結合: コンポーネントが不要なデータに依存するため、疎結合性が失われます 36

解決策1:コンポーネント合成(Composition) — React公式の推奨

多くの開発者がProp Drillingの解決策として即座に「Context API」を思い浮かべますが、Reactの公式ドキュメントは、まず「コンポーネント合成」という、よりシンプルな解決策を検討するよう強く推奨しています 18

これは、セクション2で解説したprops.childrenを活用するパターンです。

悪い例(Prop Drilling) 35

Sidebarはuserを必要としないのに、Propsとして受け取っている。

JavaScript

function App() {
  const user = { name: ‘Alice’ };
  return <Sidebar user={user} />;
}
function Sidebar({ user }) {
  // Sidebarはuserを使わない
  return <Profile user={user} />;
}
function Profile({ user }) {
  return <Avatar user={user} />;
}
function Avatar({ user }) {
  return <img alt={user.name} />;
}

良い例(Composition) 18

Sidebarはchildrenを受け取るだけにし、userの存在を知らない。

JavaScript

function App() {
  const user = { name: ‘Alice’ };
  return (
    // App側で、データを必要とするコンポーネント(Profile)を
    // レイアウトコンポーネント(Sidebar)の ‘children’ として渡す
    <Sidebar>
      <Profile user={user} />
    </Sidebar>
  );
}
function Sidebar({ children }) {
  // Sidebarはレイアウトに専念し、userの存在を知らない
  return <div className=”sidebar”>{children}</div>;
}
function Profile({ user }) {
  return <Avatar user={user} />;
}
//…

React公式がProp Drillingの第一の解決策としてContext API 18 ではなく、コンポーネント合成 18 を挙げている点は非常に重要です。合成は、Context APIが導入する「暗黙的な依存関係」や「パフォーマンス問題」(後述)なしに、コンポーネントの関心事を明確に分離します。Sidebarはレイアウトに専念し、Profileはデータの表示に専念できます。開発者は安易にContext APIに飛びつくべきではありません。

解決策2:Context API — 「テレポート」させる技術

コンポーネント合成パターンが適さない場合、Context APIが有効です。例えば、アプリケーションの非常に多くの場所で、かつ深くネストした場所で「現在のテーマ(ダークモードか否か)」や「認証ユーザー情報」にアクセスしたい場合です 43

Contextは、データをPropsで手動でバケツリレーすることなく、コンポーネントツリー全体に「テレポート」させる(ブロードキャストする)仕組みを提供します 18

Provider(データを提供する側)とuseContextフック(データを消費する側)を使って実現します 35

JavaScript

// 1. Contextオブジェクトを作成
const UserContext = React.createContext(null);

// 2. App全体を Provider でラップし、’value’ としてデータを渡す
function App() {
  const user = { name: ‘Paulo’ }; //
  return (
    <UserContext.Provider value={user}>
      <Page />
    </UserContext.Provider>
  );
}

// 3. 途中のコンポーネントはPropsを一切必要としない
function Page() { return <Sidebar />; }
function Sidebar() { return <Profile />; }

// 4. データを必要とするコンポーネントが ‘useContext’ で直接データにアクセス
function Profile() {
  const user = useContext(UserContext); //
  return <p>Name: {user.name}</p>;
}

Props設計の分岐点:Context API vs Redux/Zustand

Context APIはProp Drillingをエレガントに解決しますが、万能ではありません。

Context APIの限界:

Context APIの最大の弱点は、パフォーマンスです。Contextのvalue(上記例のuser)が更新されると、そのContextを消費(useContext(UserContext))しているすべてのコンポーネントが、たとえその変更に関係のないデータ部分だけを使っていたとしても、強制的に再レンダリングされます 45。

Global Stateライブラリの利点:

Redux 47 や Zustand 49 といったグローバル状態管理ライブラリは、この問題を解決します。これらのライブラリは、「セレクタ」を通じて、コンポーネントが巨大なStateオブジェクトの*特定のスライス(一部分)*だけを購読することを可能にします。これにより、関係のないStateが変更されても、コンポーネントは再レンダリングされません 49。

Context APIが引き起こすこの「不要な再レンダリング」 45 こそが、ZustandやReduxのようなグローバル状態管理ライブラリが依然として必要とされる最大の理由です。

これらの知見から、以下の技術選定フレームワークを導き出すことができます。

  1. Props (1〜2階層): まずはPropsで明示的に渡すことを検討します 51
  2. Composition (3+階層, UI分離): Prop Drillingが始まったら、まずコンポーネント合成(children)で解決できないか検討します 18
  3. Context API (グローバル, 低頻度更新): 合成が難しく、「低頻度で更新される」グローバルなデータ(例:テーマ、ユーザー認証情報)に使います 45
  4. Global State (Zustand/Redux) (グローバル, 高頻度更新): 「高頻度で更新される」グローバルなデータ、または状態変更ロジックが複雑な場合に選択します 48

【テーブル2:状態・データ伝達パターンのトレードオフ比較】

パターン概要ベストケース考慮事項(アンチパターン)
Props (直接渡し)親から子へ明示的にデータを渡す 21〜2階層下のコンポーネントへのデータ渡し。3階層以上になるとProp Drillingが発生する 37
Component Composition (children)JSXをPropsとして渡し、描画を親に委ねる 18UIの「枠(Frame)」と「中身(Content)」を分離したい場合 16中身が枠の外部にあるデータ(例:兄弟コンポーネントの状態)にアクセスする必要がある場合、結局Drillingになる 53
Context APIツリー全体にデータを「ブロードキャスト」する 40低頻度更新のグローバルデータ(テーマ、認証など) 43高頻度更新 52。Contextの値が変更されると、全消費者が再レンダリングされる 45
Global State (Zustand/Redux)アプリケーション外部のストアで状態を集中管理する 50高頻度更新、複雑な状態、多くのコンポーネントが共有するデータ 48シンプルなアプリにはオーバーキル(過剰設計) 54。Reduxのボイラープレート(記述量の多さ) 49

セクション5:型安全なProps:TypeScriptによる最新のベストプラクティス(2025年版)

現代のReact開発(2025年)において、TypeScriptはデファクトスタンダードとなっています 55。Propsに型を付けることは、コードの品質、保守性、開発者体験(DX)を向上させる上で不可欠です 57

interface vs type:React Propsの型定義、どちらを選ぶべきか

TypeScriptには、オブジェクトの型を定義する方法としてinterfaceとtypeの2種類があり、コミュニティで長年議論されてきました 59

  • interface の特徴:
  • extendsキーワードを使った「継承」が可能で、オブジェクト指向プログラミング(OOP)に慣れた開発者にとって直感的です 59
  • **「宣言のマージ(Declaration Merging)」**をサポートします。これは、既存のinterface(特にサードパーティライブラリの型)に後からプロパティを追加(拡張)する際に非常に強力です 61
  • type の特徴:
  • ユニオン型(|)やインターセクション型(&)など、interfaceよりも複雑で柔軟な型操作が得意です 59
  • プリミティブ型やタプル型にも別名を付けられます 60
  • 関数型プログラミングと相性が良いとされ、Reactコミュニティでの人気が高まっています 59

このinterface 62 vs type 59 の議論の現実的な結論は、「どちらでも機能するが、プロジェクト内での一貫性が最も重要」 62 というものです。

実用的な指針としては、「サードパーティの型をマージ(拡張)する必要がある場合はinterfaceを使い、それ以外(特にユニオン型などが必要な場合)はtypeを使う」という使い分け 61、あるいは「一貫性を保つために、より柔軟なtypeに統一する」 59 というのが現代的な落とし所です。

childrenの型定義:React.FCはもう使うべきではない?

ReactとTypeScriptの組み合わせで、childrenの型定義は歴史的に混乱があるポイントです。

  • 背景: 以前は、React.FC(またはReact.FunctionComponent)という型を使うと、childrenプロパティが暗黙的にPropsの型に含まれていました 63
  • React 18での変更: React 18の型定義アップデートで、React.FCからこの暗黙的なchildrenが削除されました 64
  • 理由: childrenは特別なものではなく、他のPropsと同様に「明示的に定義されるべき」である、という考え方への転換です 64。React.FCを使っていると、そのコンポーネントが実際にはchildrenを想定していない(使わない)場合でも、childrenを渡せてしまうため、バグの温床になっていました。

現代の型付け(React.FCを使わない方法)

現在のベストプラクティスは、React.FCを使わず、Propsの型定義にchildrenを明示的に含めることです 63。

TypeScript

import type { ReactNode } from ‘react’;

// Propsの型に ‘children’ を明示的に含める
type MyComponentProps = {
  title: string;
  children: ReactNode; // childrenが必須の場合
  // children?: ReactNode; // childrenがオプショナルの場合
};

// React.FC を使わずに、引数に直接型を適用する
export const MyComponent = ({ title, children }: MyComponentProps) => {
  return (
    <div>
      <h2>{title}</h2>
      {children}
    </div>
  );
};

childrenを明示的に追加するPropsWithChildrenというヘルパー型も存在しますが 65、上記のように型定義に直接childrenを記述する方が、コンポーネントのAPIがより明確になります。

ユーティリティ型:PickとOmitでPropsを賢く扱う

TypeScriptのユーティリティ型は、既存のProps型を再利用し、 DRY(Don’t Repeat Yourself)な型定義を実現するのに非常に強力です 67

  • Pick<Type, Keys>: Typeから指定したKeysのプロパティだけを選び出し、新しい型を作ります 67
  • Omit<Type, Keys>: Typeから指定したKeysのプロパティを除外し、新しい型を作ります 68

Omitは、コンポーネントのラッパーを作る際に絶大な威力を発揮します 69。

例えば、外部ライブラリのExternalComponentをラップするInternalComponentを作るとします。InternalComponentは、ExternalComponentのPropsをすべて受け入れつつ、classNameだけはInternalComponentが制御し、代わりにouterClassNameという独自のPropを追加したい、というケースです 70。

TypeScript

import { ComponentProps } from ‘react’;
import { ExternalComponent } from ‘external-lib’;

// 1. ComponentProps<T> を使い、ExternalComponent のProps型を取得
// 2. Omit<T, K> を使い、’className’ プロパティだけを除外
// 3. ‘&’ (インターセクション) を使い、独自の ‘outerClassName’ プロパティを追加
type InternalComponentProps =
  Omit<ComponentProps<typeof ExternalComponent>, ‘className’> &
{
  outerClassName: string;
};

const InternalComponent = ({
  outerClassName,
…restProps // Omitされた残りのPropsがすべて入る
}: InternalComponentProps) => (
  <div className={outerClassName}>
    {/* 外部コンポーネントには残りのPropsをスプレッド構文で渡す */}
    <ExternalComponent {…restProps} />
  </div>
);

セクション6:【最新動向】React Server Components (RSC) とPropsの未来

React 19 56 で本格的に導入されるReact Server Components (RSC) は、Propsの扱いや制約に関して、Reactの歴史上最も大きなパラダイムシフトをもたらします 72

RSCとは何か? なぜPropsの常識が変わるのか

RSCは、従来のReactコンポーネント(現在は区別のため「Client Components」と呼ばれる)とは異なり、サーバーサイド専用で(ビルド時またはリクエスト時に)実行されるコンポーネントです 71

RSCの最大の特徴は、クライアント(ブラウザ)にJavaScriptバンドルを送信しないことです 72

Propsのシリアライズ(直列化)とは?

従来のSSR(サーバーサイドレンダリング)がHTML文字列をクライアントに送信していたのに対し 75、RSCはHTMLを直接送るわけではありません 76

RSCは、「RSC Payload」 77 と呼ばれる、レンダリング結果(どのコンポーネントが、どのPropsで、どの順番で描画されるか)を記述した、特別なJSON風のデータ形式 72 をクライアントに送信します。

これにより、Propsに関する新しい、そして非常に厳格なルールが生まれました。

Server ComponentからClient ComponentへPropsを渡す際、そのPropsはもはやメモリ内の参照ではなく、ネットワーク経由で送信可能な**「シリアライズ(直列化)可能」**な値でなければなりません 78。

最大の制約:「Client Componentに関数を渡せない」問題

このシリアライズのルールの最大の帰結は、**「関数はシリアライズできない」**という事実です 78

これにより、Reactの基本的なパターンであった「イベントハンドラをPropsとして渡す」ことが、Server ComponentからClient Componentへ渡す際には原則として禁止されました 80

JavaScript

// MyServerComponent.js (Server Component)
import ClientButton from ‘./ClientButton’;

function MyServerComponent() {
  function handleClick() {
    // この関数はサーバー側にしか存在しない
    console.log(“Clicked on server”);
  }

  // 致命的エラー:
  // 関数 (handleClick) はシリアライズ不可なため、
  // Client Component にPropsとして渡せない
  return <ClientButton onClick={handleClick} />;
}

// ClientButton.js (Client Component)
‘use client’;
export default function ClientButton({ onClick }) {
  // サーバーから onClick 関数を受け取れない
  return <button onClick={onClick}>Click Me</button>;
}

この「関数を渡せない」制約には、**「Server Actions」**という重要な例外があります 81。関数に”use server”というディレクティブをファイルの先頭か関数自体に付与する 81 と、Reactはその関数自体をシリアライズする代わりに、クライアント側に「この関数を呼び出すためのネットワークリクエストを行うスタブ(代理)」を渡します。これにより、クライアントの操作(例:フォームの送信)がサーバー上の関数を直接呼び出す(RPC: リモートプロシージャコール)ことが可能になります。

解決策:コンポーネントをPropsとして渡す正しい方法(JSX vs 関数)

では、Server Component(例:サーバーでデータをフェッチする<UserProfile />)を、Client Component(例:タブ切り替えUI)のPropsとして渡すにはどうすればよいでしょうか? 83

この違いを理解することが、RSCにおけるPropsの概念を理解する鍵となります 83

間違った方法(コンポーネントの「関数」を渡す) 83

JavaScript

// Parent.js (Server Component)
import ClientTabs from ‘./ClientTabs’;
import UserProfile from ‘./UserProfile’; // (Server Component)

// エラー: ‘UserProfile’ はコンポーネント関数そのもの。
// 関数はシリアライズできないため渡せない。
return <ClientTabs slot1={UserProfile} />;

正しい方法(コンポーネントの「JSX要素」を渡す) 83

JavaScript

// Parent.js (Server Component)
import ClientTabs from ‘./ClientTabs’;
import UserProfile from ‘./UserProfile’; // (Server Component)

// OK: ‘<UserProfile />’ はJSX要素 (React Element)。
// これはシリアライズ可能な値として渡せる。
return <ClientTabs slot1={<UserProfile />} />;

なぜJSX(<UserProfile />)なら渡せるのでしょうか?

これは、slot1={UserProfile}が「コンポーネントの関数(コード)そのもの」を渡そうとするのに対し、slot1={<UserProfile />}は「サーバーサイドで<UserProfile />を先にレンダリングし、その結果(RSC Payloadの一部であるシリアライズされたUIオブジェクト)」を渡しているからです 72

Client ComponentであるClientTabsは、UserProfileコンポーネントのコードや関数を一切受け取りません。ただ、slot1というPropsに、既にレンダリング済みの「静的なUIの断片(シリアライズされたオブジェクト)」 73 を受け取るだけです。これは、RSCにおける「コンポーネント合成」の新しい形であり、props.children 73 もこの仕組みで機能しています。

セクション7:結論 — Propsマスターへの道

ReactのPropsは、その誕生から 3、React 19とServer Componentsの時代 73 に至るまで、Reactのコンポーネントベースの設計思想の核であり続けています。

Propsの概念は、「親から子への読み取り専用データ」 9 という基本的な役割から、TypeScriptによる「型安全なAPIコントラクト」 58 へと進化しました。

そしてRSCの登場により、Propsは新たに「サーバーとクライアントの境界線を跨ぐ、シリアライズ可能なペイロード」 77 という重要な側面を獲得しました。

Propsの基本的な原則(単方向データフロー、不変性)を深く理解し、その上でchildrenやContext APIといったアーキテクチャパターンを使いこなし、React.memoでパフォーマンスを最適化し、TypeScriptでその振る舞いを厳密に定義し、最終的にRSCのシリアライズ制約に適応すること。これらすべてをマスターすることが、現代のReactエキスパートへの道です。

引用文献

  1. React Components, Props, and JSX: A Beginner’s Guide – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/a1guy/react-components-props-and-jsx-a-beginners-guide-50ae
  2. React Props Explained With Examples – Built In, 11月 15, 2025にアクセス、 https://builtin.com/articles/react-props
  3. Components and Props – React, 11月 15, 2025にアクセス、 https://legacy.reactjs.org/docs/components-and-props.html
  4. Passing Props to a Component – React, 11月 15, 2025にアクセス、 https://react.dev/learn/passing-props-to-a-component
  5. React Components and Their Types: A Real-Life Analogy. | by Shivam Jha | Medium, 11月 15, 2025にアクセス、 https://medium.com/@shivamjha2436/react-components-and-their-types-a-real-life-analogy-1a6f66d9c89a
  6. What Are Props in React? – GeeksforGeeks, 11月 15, 2025にアクセス、 https://www.geeksforgeeks.org/reactjs/what-are-props-in-react/
  7. A Simple Guide to Component Props in React, 11月 15, 2025にアクセス、 https://dmitripavlutin.com/react-props/
  8. How Props Work in React – A Beginner’s Guide – freeCodeCamp, 11月 15, 2025にアクセス、 https://www.freecodecamp.org/news/beginners-guide-to-props-in-react/
  9. React Props Explained with Examples – Refine dev, 11月 15, 2025にアクセス、 https://refine.dev/blog/react-props/
  10. React State Vs Props – YouTube, 11月 15, 2025にアクセス、 https://www.youtube.com/watch?v=IYvD9oBCuJI
  11. Thinking in React, 11月 15, 2025にアクセス、 https://react.dev/learn/thinking-in-react
  12. React Props vs State: What’s the Difference? – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/highflyer910/react-props-vs-state-whats-the-difference-4e3i
  13. What is the difference between state and props? | by Prathap – Medium, 11月 15, 2025にアクセス、 https://prathapreddy-mudium.medium.com/what-is-the-difference-between-state-and-props-34c9d8bfcbfd
  14. 11月 15, 2025にアクセス、 https://react.dev/reference/react/Children#:~:text=In%20React%2C%20the%20children%20prop,represented%20as%20an%20array%20internally.
  15. Understanding props.children in React with an example | by Naveen Mathews Renji, 11月 15, 2025にアクセス、 https://naveenrenji.medium.com/understanding-props-children-in-react-with-an-example-e4e0b446358a
  16. A quick intro to React’s props.children | by Jason Arnold | codeburst, 11月 15, 2025にアクセス、 https://codeburst.io/a-quick-intro-to-reacts-props-children-cb3d2fce4891
  17. React.js: Using Children Props – by Martin Crabtree – Medium, 11月 15, 2025にアクセス、 https://medium.com/@martin.crabtree/react-js-using-children-props-c83d5b259756
  18. Passing Data Deeply with Context – React, 11月 15, 2025にアクセス、 https://react.dev/learn/passing-data-deeply-with-context
  19. How to Use and Pass Functions as Props— React | by Kenneth Kim – Medium, 11月 15, 2025にアクセス、 https://medium.com/@kkm2059/how-to-use-and-pass-functions-as-props-react-ff677f5bca0b
  20. JSX Spread Attributes | React, 11月 15, 2025にアクセス、 https://zhenyong.github.io/react/docs/jsx-spread.html
  21. react-props-spreading – Semgrep, 11月 15, 2025にアクセス、 https://semgrep.dev/r/typescript.react.best-practice.react-props-spreading.react-props-spreading?utm_campaign=finding_notification&utm_medium=review_comment&utm_source=github&utm_content=rule
  22. A complete guide to React default props – LogRocket Blog, 11月 15, 2025にアクセス、 https://blog.logrocket.com/complete-guide-react-default-props/
  23. Default parameters – JavaScript – MDN Web Docs, 11月 15, 2025にアクセス、 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
  24. React – defaultProps vs ES6 default params when destructuring (performances issues), 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/41488537/react-defaultprops-vs-es6-default-params-when-destructuring-performances-issu
  25. React functional component default props vs default parameters – Stack Overflow, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/47774695/react-functional-component-default-props-vs-default-parameters
  26. When to wrap React.memo for a component? : r/reactjs – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/reactjs/comments/15qelc5/when_to_wrap_reactmemo_for_a_component/
  27. memo – React, 11月 15, 2025にアクセス、 https://react.dev/reference/react/memo
  28. Use React.memo() wisely, 11月 15, 2025にアクセス、 https://dmitripavlutin.com/use-react-memo-wisely/
  29. React.memo — Optimize React Functional Components | by Vivek Malhan – Medium, 11月 15, 2025にアクセス、 https://medium.com/@amalhan43/react-memo-optimize-react-functional-components-0e42f91e6579
  30. React Memo Guide with Examples – Refine dev, 11月 15, 2025にアクセス、 https://refine.dev/blog/react-memo-guide/
  31. How to use React.memo to optimize performance – Stack Overflow, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/64935189/how-to-use-react-memo-to-optimize-performance
  32. When should you NOT use React memo? – Stack Overflow, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/53074551/when-should-you-not-use-react-memo
  33. What is React memo and how to use it? – Hygraph, 11月 15, 2025にアクセス、 https://hygraph.com/blog/react-memo
  34. Optimizing Performance – React, 11月 15, 2025にアクセス、 https://legacy.reactjs.org/docs/optimizing-performance.html
  35. Understanding Prop Drilling and How to Solve It – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/paulocappa/understanding-prop-drilling-and-how-to-solve-it-2bnd
  36. Prop Drilling in React Explained with Examples – freeCodeCamp, 11月 15, 2025にアクセス、 https://www.freecodecamp.org/news/prop-drilling-in-react-explained-with-examples/
  37. Prop Drilling in React: What It Is and How to Avoid It | by Tayyeb Shahzad, 11月 15, 2025にアクセス、 https://medium.com/@tayyebbutt1/prop-drilling-in-react-what-it-is-and-how-to-avoid-it-3b50e870e765
  38. 11月 15, 2025にアクセス、 https://www.angularminds.com/blog/what-is-prop-drilling-in-react#:~:text=Prop%20drilling%20in%20React%20occurs,coupled%20components%2C%20and%20performance%20issues.
  39. Understanding Prop Drilling and How to Avoid It | by Narayanan Sundaram | Medium, 11月 15, 2025にアクセス、 https://medium.com/@narayanansundar02/understanding-prop-drilling-in-react-and-how-to-avoid-it-da2639a9e41a
  40. State Management in React: Props Drilling vs. Context API | by Arunangshu Das – Medium, 11月 15, 2025にアクセス、 https://arunangshudas.medium.com/state-management-in-react-props-drilling-vs-context-api-24caaa78bfde
  41. 11月 15, 2025にアクセス、 https://legacy.reactjs.org/docs/context.html#:~:text=Context%20is%20primarily%20used%20when,a%20simpler%20solution%20than%20context.
  42. Composition vs Context in React – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/bhupendra1011/composition-vs-context-in-react-5cmb
  43. Context – React, 11月 15, 2025にアクセス、 https://legacy.reactjs.org/docs/context.html
  44. Say Goodbye to Prop Drilling! Learn useContext in React Like a Pro – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/chintanonweb/say-goodbye-to-prop-drilling-learn-usecontext-in-react-like-a-pro-451e
  45. State Management in React –Props vs the Context API – freeCodeCamp, 11月 15, 2025にアクセス、 https://www.freecodecamp.org/news/state-management-in-react-props-vs-context-api/
  46. State Management in React: Context API Vs State Management libraries like Redux, Recoil, Zustand, etc. | by Manish Rai | Medium, 11月 15, 2025にアクセス、 https://medium.com/@raimanishthl08/state-management-in-react-context-api-vs-state-management-libraries-like-redux-recoil-zustand-24fc8fd59f86
  47. Context API Vs. Redux – GeeksforGeeks, 11月 15, 2025にアクセス、 https://www.geeksforgeeks.org/blogs/context-api-vs-redux-api/
  48. Redux Vs Context-API. As React has risen in popularity as one… | by Tanya sharma | Medium, 11月 15, 2025にアクセス、 https://medium.com/@tanyas022000/redux-vs-context-api-45e5bae61df2
  49. React: Context API vs Zustand vs Redux | by Codenova – Medium, 11月 15, 2025にアクセス、 https://medium.com/@codenova/react-context-api-vs-zustand-vs-redux-472d05afb6ee
  50. State management in React: Context API vs. Zustand vs. Redux – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/mspilari/state-management-in-react-context-api-vs-zustand-vs-redux-3ahk
  51. When to use Store (Zustand) vs Context vs Redux ? : r/react – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/react/comments/1g6ci6n/when_to_use_store_zustand_vs_context_vs_redux/
  52. State Management: When to Use Context API vs. Redux? : r/react – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/react/comments/1fp27ek/state_management_when_to_use_context_api_vs_redux/
  53. Why component composition as an alternative to Context? – Stack Overflow, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/76880091/why-component-composition-as-an-alternative-to-context
  54. Redux vs Context API: When to use them – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/ruppysuppy/redux-vs-context-api-when-to-use-them-4k3p
  55. TypeScript Best Practices in 2025 – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/mitu_mariam/typescript-best-practices-in-2025-57hb
  56. React Design Patterns and Best Practices for 2025 – Telerik.com, 11月 15, 2025にアクセス、 https://www.telerik.com/blogs/react-design-patterns-best-practices
  57. 10 Compelling Reasons to Use TypeScript with React in 2024 | by Chirag Dave – Medium, 11月 15, 2025にアクセス、 https://medium.com/@chirag.dave/10-compelling-reasons-to-use-typescript-with-react-in-2024-cc43a41d97ca
  58. React with TypeScript: Best Practices – SitePoint, 11月 15, 2025にアクセス、 https://www.sitepoint.com/react-with-typescript-best-practices/
  59. [TS] Do you prefer using type or interface to define props? : r/reactjs – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/reactjs/comments/vzoqdv/ts_do_you_prefer_using_type_or_interface_to/
  60. Types vs. interfaces in TypeScript – LogRocket Blog, 11月 15, 2025にアクセス、 https://blog.logrocket.com/types-vs-interfaces-typescript/
  61. Interface vs Type. What should I use in react/typescript : r/reactjs – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/reactjs/comments/14q6nyr/interface_vs_type_what_should_i_use_in/
  62. Choosing Between “type” and “interface” in React | by Daniel Leitch | Nerd For Tech, 11月 15, 2025にアクセス、 https://medium.com/nerd-for-tech/choosing-between-type-and-interface-in-react-da1deae677c9
  63. Typescript React, best way to define component with props? : r/reactjs – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/reactjs/comments/152zs2q/typescript_react_best_way_to_define_component/
  64. javascript – React 18 TypeScript children FC – Stack Overflow, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/71788254/react-18-typescript-children-fc
  65. PropsWithChildren vs ReactNode in TypeScript | by Zar Nabi – Medium, 11月 15, 2025にアクセス、 https://medium.com/@colorsong.nabi/propswithchildren-vs-reactnode-in-typescript-c3182cbf7124
  66. Unsafe ‘PropsWithChildren’ Utility type in React TypeScript App – DEV Community, 11月 15, 2025にアクセス、 https://dev.to/maafaishal/unsafe-propswithchildren-utility-type-in-react-typescript-app-3bd3
  67. TypeScript Utility Types: Pick, Omit, Partial, and More | by Frontend Highlights | Medium, 11月 15, 2025にアクセス、 https://medium.com/@ignatovich.dm/typescript-utility-types-pick-omit-partial-and-more-ae2a46f020a5
  68. Documentation – Utility Types – TypeScript, 11月 15, 2025にアクセス、 https://www.typescriptlang.org/docs/handbook/utility-types.html
  69. The TypeScript Omit utility type – Graphite, 11月 15, 2025にアクセス、 https://graphite.dev/guides/typescript-omit-utility-type
  70. 7 TypeScript Utility Types For React Developers | A technical blog by Chak Shun Yu, 11月 15, 2025にアクセス、 https://www.chakshunyu.com/blog/7-typescript-utility-types-for-react-developers/
  71. React 19 and Beyond — Deep Dive into React Server Components (RSC) and the Future of Frontend Architecture | by Saniya | Oct, 2025 | Medium, 11月 15, 2025にアクセス、 https://medium.com/@beenakumawat003/%EF%B8%8F-react-19-and-beyond-deep-dive-into-react-server-components-rsc-and-the-future-of-frontend-afa7db852bf5
  72. Making Sense of React Server Components • Josh W. Comeau, 11月 15, 2025にアクセス、 https://www.joshwcomeau.com/react/server-components/
  73. Server Components – React, 11月 15, 2025にアクセス、 https://react.dev/reference/rsc/server-components
  74. Understanding React Server Components – Vercel, 11月 15, 2025にアクセス、 https://vercel.com/blog/understanding-react-server-components
  75. What is the difference between React Server Components (RSC) and Server Side Rendering (SSR)? – Stack Overflow, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/76325862/what-is-the-difference-between-react-server-components-rsc-and-server-side-ren
  76. Hype Around React Server Components… Am I Missing Something? : r/nextjs – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/nextjs/comments/1jyk3w5/hype_around_react_server_components_am_i_missing/
  77. Getting Started: Server and Client Components – Next.js, 11月 15, 2025にアクセス、 https://nextjs.org/docs/app/getting-started/server-and-client-components
  78. How React server components work: an in-depth guide | Plasmic Blog, 11月 15, 2025にアクセス、 https://www.plasmic.app/blog/how-react-server-components-work
  79. Why you cant pass function as properties to server components and client components? | by Ravi Chandola | Javarevisited | Medium, 11月 15, 2025にアクセス、 https://medium.com/javarevisited/why-you-cant-pass-function-as-properties-to-server-components-and-client-components-813103cd500e
  80. Passing down function from Server components to Client components : r/nextjs – Reddit, 11月 15, 2025にアクセス、 https://www.reddit.com/r/nextjs/comments/12ds6mj/passing_down_function_from_server_components_to/
  81. ‘use server’ directive – React, 11月 15, 2025にアクセス、 https://react.dev/reference/rsc/use-server
  82. React Server Component Error: Server Functions can not be called during initial render, 11月 15, 2025にアクセス、 https://stackoverflow.com/questions/76761493/react-server-component-error-server-functions-can-not-be-called-during-initial
  83. Passing Server Components to Client Components as Props – Docs …, 11月 15, 2025にアクセス、 https://github.com/vercel/next.js/discussions/63301
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次