こんにちは!Reactの学習、毎日お疲れ様です。
コンポーネントを組み合わせて画面を作っていく楽しさが分かってきた一方で、「あれ、このデータはどうやって親から子へ渡すんだっけ?」「Propsの型付けってどうやるんだっけ……」と、頭がモヤモヤする瞬間、ありますよね。大丈夫です、誰もが最初はそこで立ち止まりますから、安心してくださいね。
さて、今回は最近のReact開発でとっても重要なテーマである「Server Components(RSC)をPropsとして渡すパターン」について、お話ししようと思います。
「Server Componentsって聞いたことはあるけど、なんだか難しそう……」
「Propsとして渡すって、どういうこと?」
そんな風に身構えてしまうかもしれませんが、身近な例えを使いながら、ひとつずつ優しくほどいていきますので、どうか肩の力を抜いてついてきてくださいね。
—
1. 「お弁当箱」の例えでイメージする、RSCとProps
まずは、今日の一番大切なイメージをつかむために、ちょっと「お弁当箱」を思い浮かべてみましょう。
あなたは今、素敵なお弁当箱(親コンポーネント)を持っています。
このお弁当箱には、ごはんやスープを入れる「決まった場所」もあれば、中身を自由に変えられる「大きなおかずカップ(スロット)」もありますよね。
- Server Components(サーバーコンポーネント):
お弁当屋さん(サーバー)の厨房で、プロの料理人たちがあらかじめ美味しく調理してくれた「完成品のハンバーグ」のようなものです。お皿の上でジュージュー焼く必要はありません。すでに出来上がっています。
- Propsとして渡す:
その出来上がった「ハンバーグ」を、お弁当箱の「おかずカップ」にポンッと入れてあげること。
React Server Components(RSC)の最大の特徴は、「サーバー側でドカンと重い処理やデータ取得を終わらせて、軽くなったHTML(完成品)をブラウザに届けてくれること」です。
この「完成品」であるRSCを、別のコンポーネントの `children` や専用のカスタムスロット(Props)としてポイッと渡してあげることで、「サーバーのパワーで作った綺麗なパーツを、クライアント側のレイアウト部品にきれいにはめ込む」という、とってもスマートな連携ができるようになるんです。
—
2. なぜ、わざわざPropsとして渡す必要があるの?
「子コンポーネントを普通にインポートして中に入れちゃダメなの?」って思いますよね。実は、ここにReactのちょっとした「壁」があります。
クライアントサイドで動くコンポーネント(`”use client”` がついているものなど)の中に、サーバーサイド専用の重いコンポーネントを直接「よいしょ」と直書きしてしまうと、データの流れやレンダリングの境界線がごちゃ混ぜになってしまい、せっかくのServer Componentsの旨みが逃げてしまうことがあるんです。
そこで登場するのが、「お弁当箱(レイアウト)はガワだけ用意して、中身の具材(RSC)は外からPropsとして受け取る」というテクニックです。
これによって、レイアウトの枠組みはスッキリ保ちつつ、中身の重たいデータ取得などはサーバー側にしっかりお任せするという、綺麗な分業体制が作れるようになります。
—
3. 実際のコードで見てみよう!
言葉だけだとフワッとしてしまうので、シンプルなコードを見てみましょう。
今回は、外枠となる「カード風の枠組み(レイアウト)」の中に、サーバー側でユーザー情報を取ってくるコンポーネントをスッポリとはめ込む例を作ってみます。
ステップ1:外枠となるコンポーネント(ラッパー)を作る
まずは、どんな中身でも包み込める「お弁当箱の容器」のようなコンポーネントです。ここでは `children` という特別なPropsを使います。
// components/CardLayout.tsx
import React, { ReactNode } from ‘react’;
// TypeScriptの型定義:childrenが受け取れるのはReactの要素だよ、と教えてあげます
interface CardLayoutProps {
title: string;
children: ReactNode; // ここにServer ComponentsなどのJSXが入ってきます!
}
export default function CardLayout({ title, children }: CardLayoutProps) {
return (
{title}
{/ 渡されてきた中身をここでパッと表示する /}
);
}
ステップ2:サーバー側でデータを取りに行くコンポーネントを作る
次に、サーバーサイドでゴリゴリとデータを取ってくる(イメージの)コンポーネントです。これが、今回の主役であるServer Componentになります。
// components/UserProfileServer.tsx
// ※ Next.jsのApp Routerなどを想定しています
// サーバー側でデータを取得する非同期コンポーネント
export default async function UserProfileServer() {
// 例として、サーバー側でのデータ取得をちょっと待つふり
// await fetch(‘https://api.example.com/user’);
const userName = “山田 太郎”;
const userRole = “シニア・フロントエンド・エンジニア”;
return (
お名前: {userName}
役職: {userRole}
✓ サーバー側で安全にデータを取得しました
);
}
ステップ3:親ページで「合成(コンポジション)」する!
さあ、いよいよ仕上げです。ページ側で、この2つをドッキングさせます。
// app/page.tsx (サーバーコンポーネント)
import CardLayout from ‘@/components/CardLayout’;
import UserProfileServer from ‘@/components/UserProfileServer’;
export default function Page() {
return (
マイページへようこそ
{/
CardLayout(枠組み)の中に、
UserProfileServer(中身のRSC)を子供(children)として渡しています!
/}
);
}
どうでしょう? `CardLayout` は中身がどんなものか知らなくても、ただ渡された `children` をきれいにレイアウトの中に配置する役割に徹しています。そして中身の `UserProfileServer` は、サーバーの力で安全にデータを取得してきて表示する。この役割分担の美しさ、伝わりますでしょうか?
—
4. つまずきやすいポイントと「大丈夫だよ」のフォロー
このパターンを学び始めの頃、よくこんなことで手が止まりがちです。
1. 「型の書き方に戸惑う……」
- フォロー: `children` や、独自のカスタムスロット(例:`headerSlot?: ReactNode` など)をPropsに持たせる時は、とりあえず `ReactNode` 型を選んでおけば大体エラーは鎮火します。TypeScriptの型エラーが出ても、「あ、今は型を優しく教えてくれているんだな」と深呼吸してくださいね。
2. 「どこまでサーバーで、どこからクライアント?」
- フォロー: 基本は「ページや大枠のレイアウトはサーバーで動かし、ボタンをクリックした時の状態管理などが必要な最小限の部分だけ `”use client”` をつける」という意識でOKです。完璧にやろうとせず、まずは動く形を作ってみるのが一番の近道ですよ。
—
まとめ
Server ComponentsをPropsとして渡すパターンは、一見すると難しそうな名前をしていますが、やっていることは「お弁当箱の枠組みと、中身の美味しいおかずを綺麗に切り分けて合体させる」という、とてもシンプルで理にかなった手法です。
このコンポーネントの組み合わせ方(コンポジション)が体に馴染んでくると、Reactでのアプリ開発が何倍も楽しく、そしてコードがスッキリと美しく書けるようになります。
焦らず、ご自身のペースで少しずつコードを書いて試してみてくださいね。あなたのReactの旅を、心から応援しています!

コメント