← 解説「組み合わせ方 — ServerからClientへpropsを渡す」に戻る
サンプルコードで身につける: 組み合わせ方 — ServerからClientへpropsを渡す
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1文字列のpropsを渡す
Server から Client へ props を渡す、組み合わせの最小形です。受け取る側は普通の React コンポーネントと同じ書き方でよく、「Server がデータを用意し、Client が操作を担当する」分担の出発点になります。
// app/greeting.tsx — Client Component
"use client";
export default function Greeting({ userName }: { userName: string }) {
return <button onClick={() => alert(userName + " さん、ようこそ")}>あいさつ</button>;
}
// app/page.tsx — Server Component
import Greeting from "./greeting";
export default function HomePage() {
const userName = "kazu"; // サーバー側で用意した値
return <Greeting userName={userName} />; // props で渡す
}
2いいねボタンに初期値を渡す
サーバーが用意した初期データ(いいね数)を Client に渡し、以降の操作はブラウザ側で完結させる例です。「最初の値はサーバー、その後の変化はクライアント」という時間軸の分担は、実務の画面のあちこちで登場します。
// app/posts/like-button.tsx — Client Component
"use client";
import { useState } from "react";
export default function LikeButton({ initialCount }: { initialCount: number }) {
// サーバーから渡された値を初期値にして、以降はブラウザで管理
const [count, setCount] = useState(initialCount);
return <button onClick={() => setCount(count + 1)}>いいね {count}</button>;
}
// app/posts/page.tsx — Server Component
import LikeButton from "./like-button";
export default function PostPage() {
const post = { title: "はじめての投稿", likes: 12 };
return (
<article>
<h1>{post.title}</h1>
<LikeButton initialCount={post.likes} />
</article>
);
}
3propsで渡せる値・渡せない値
Server から Client への props は「シリアライズしてネットワーク越しに送れる値」だけ、という制約を JSON 化で疑似的に確かめる例です。関数を渡そうとしてエラーになったとき、この目安を知っていると原因にすぐたどり着けます。
TypeScript
4childrenでServerの中身を包む
Client Component の children に Server Component の内容をそのまま入れられる、という組み合わせ方の例です。「開閉の動きだけ Client、中の重い表示は Server のまま」にでき、Client 化する範囲を最小限に保つ実務テクニックです。
// app/accordion.tsx — 開閉の動きだけ担当する Client Component
"use client";
import { useState } from "react";
export default function Accordion({ children }: { children: React.ReactNode }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>詳細を{isOpen ? "閉じる" : "開く"}</button>
{isOpen && children} {/* 中身はサーバーで作られたものをそのまま表示 */}
</div>
);
}
// app/page.tsx — Server Component
import Accordion from "./accordion";
export default function HomePage() {
return (
<Accordion>
<p>この中身は Server Component のまま。開閉だけが Client の仕事。</p>
</Accordion>
);
}
5記事ページの実務的な分担
実務の記事ページを「表示は Server、操作は Client」で分割した全体像の例です。本文やタイトルの表示はサーバーで HTML 化して速く届け、いいねとシェアのボタンだけを小さな Client Component に切り出す、レッスン本文の方針の完成形です。
// app/blog/[id]/page.tsx — ページ全体は Server Component
import LikeButton from "./like-button"; // "use client" の小さな部品
import ShareButton from "./share-button"; // 同上
export default async function PostPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const post = { id, title: "記事 " + id, body: "本文..." , likes: 12 };
return (
<article>
<h1>{post.title}</h1> {/* 表示だけ → Server のまま */}
<p>{post.body}</p>
{/* 操作が必要な部分だけ Client に切り出して props を渡す */}
<LikeButton initialCount={post.likes} />
<ShareButton postTitle={post.title} />
</article>
);
}