【実務・中級編】 Render Propsパターンの概念 – React実践ガイド

Render Props:なぜ「コンポーネントの責務」を関数に委ねるのか

現場でコードを読んでいると、たまに「Propsとして関数を渡して、その戻り値をレンダリングする」という奇妙なコンポーネントに出会うことはないだろうか?

そう、それが今回語るRender Propsパターンだ。

正直に言おう。現代のReactにおいて、Hooksが登場して以来、Render Propsの出番は確実に減った。しかし、それでもなおこのパターンが「伝説のアーキテクチャ」として語り継がれ、今もなお実務で最強の武器になる局面がある。

今日は、小手先のテクニックではなく、なぜこのパターンが「疎結合で再利用性の高い設計」を実現するのか、その本質を紐解いていこう。

—

1. Render Propsの正体:レンダリングの「外注」

Render Propsの本質は「コンポーネント自身が描画内容を決めず、親から渡された『描画ロジック(関数)』にその判断を委ねること」にある。

ブラウザの裏側、つまりReactのFiberアーキテクチャから見れば、これは単なる「関数の実行」だ。親から渡された関数を実行し、その結果返ってきたReact要素をDOMツリーの中に組み込む。たったこれだけのことだが、これによって「ロジック(状態管理)」と「UI(見栄え)」を完全に切り離すことができる。

なぜこれが強力なのか?

もしあなたが、複数の場所で「同じデータフェッチや状態管理ロジック」を使うが、「UIは場所ごとに全く異なる」という画面を実装しなければならないとしたら、どうする?
コンポーネントの中にUIをハードコードすれば、条件分岐(if文)の地獄が待っている。Render Propsを使えば、ロジックだけを抽出した「空っぽの器」を作り、UIを注入するだけで済むんだ。

—

2. 実践:型安全なRender Propsの実装

TypeScript環境でRender Propsを書く際、多くのエンジニアが「型の付け方がわからん!」と詰まる。ここはスマートに解決しよう。ジェネリクスを活用するのがプロのやり方だ。

import React, { useState, useEffect } from ‘react’;

// 状態を管理するロジック(データフェッチなどを想定)
type DataProviderProps = {
// childrenを関数として受け取る。これがRender Propsの肝。
// 引数に状態を渡し、戻り値としてJSXを期待する。
children: (data: T | null, isLoading: boolean) => React.ReactNode;
};

export const DataProvider = ({ children }: DataProviderProps) => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
// ここでAPIを叩くなど、共通のロジックが走る
setTimeout(() => {
setData({ message: “データ取得成功!” } as T);
setIsLoading(false);
}, 1000);
}, []);

// UIを自分で持たず、渡された関数を実行して結果を返す
return <>{children(data, isLoading)};
};

// 【利用側】UIの責務をここに閉じ込める
const App = () => {
return (
>
{(data, isLoading) => {
if (isLoading) return

読み込み中…

;
return

{data?.message}

;
}}

);
};

—

3. なぜHooksがあるのにRender Propsを使うのか?

「いや、それHooksで書けるよね?」と思った君は鋭い。その通りだ。`useData()` というカスタムフックを作れば、大抵のケースは解決する。

しかし、Render Propsが輝くのは「JSXの中にロジックを宣言的に記述したい時」だ。

1. コンポーネントの合成(Composition): 複数のProviderを重ねる際、Hooksだと「useA(); useB(); useC(); …」と定義が並ぶが、Render PropsならJSXの階層構造として視覚的に依存関係を理解できる。
2. 特定のライフサイクルへの介入: コンポーネントの「描画直前」や「特定のタイミング」でレンダリングを制御したい場合、関数として渡すRender Propsの方が、制御のタイミングが直感的になることがある。

—

4. 現場のシニアからのアドバイス

Render Propsを使うときに一つだけ気をつけてほしいことがある。それは「無名関数の再生成による不要な再レンダリング」だ。

もしRender Propsに渡す関数を`useCallback`でメモ化せず、インラインでそのまま書くと、親コンポーネントが再レンダリングされるたびに「新しい関数(参照)」が生成され、子コンポーネントが毎回再レンダリングされてしまう。

パフォーマンスを気にするなら、こうするんだ。

// 良い例:useCallbackで関数を固定する
const renderContent = useCallback((data: any) => (

), []); // 依存配列が空なら再生成されない

return {renderContent};

まとめ

Render Propsは、UIを「データ」ではなく「振る舞い」として扱うための高度な手法だ。

  • ロジックの再利用: 状態管理を抽象化して、UIを差し替える。
  • 型の活用: ジェネリクスを使って、型安全にデータを流し込む。
  • パフォーマンス: 関数参照のメモ化を忘れない。

このパターンを使いこなせるようになると、君が作るコンポーネントは「ただのUI部品」から「洗練されたロジックの基盤」へと進化する。次のコードレビューでは、ぜひこの視点を取り入れてみてほしい。

何かあれば、いつでもコードを見せに来てくれ。一緒に最高のものを作ろう。

コメント

タイトルとURLをコピーしました