App RouterではデフォルトがServer Components。"use client"ディレクティブを追加するとClient Componentになる。
// ── Server Component(デフォルト)────────────────────
// async/await を使って直接DBやAPIを呼べる
// JavaScript がブラウザに送られない → 軽い
async function UserList() {
const users = await fetch("https://api.example.com/users", {
cache: "no-store" // キャッシュなし(常に最新を取得)
}).then(r => r.json());
return (
<ul>
{users.map((u: User) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
// ── Client Component ───────────────────────────────────
// ファイルの先頭に "use client" を書く → ブラウザで動く
// useState・useEffect・イベントハンドラを使いたい場合はClient
// "use client"; ← 実際のコードではこう書く
import { useState } from "react";
function LikeButton({ postId }) {
const [liked, setLiked] = useState(false);
const [count, setCount] = useState(0);
const handleLike = () => {
setLiked(l => !l);
setCount(c => c + (liked ? -1 : 1));
};
return (
<button onClick={handleLike}>
{liked ? "❤️" : "🤍"} {count}
</button>
);
}
// ── 組み合わせ方 ───────────────────────────────────────
// Server Component の中に Client Component を入れられる
// → サーバーでデータ取得 → クライアントでインタラクション
async function PostPage({ id }) {
const post = await getPost(id); // サーバーでDBから取得
return (
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
<LikeButton postId={post.id} /> {/* インタラクション部分だけClient */}
</article>
);
}"use client"はコンポーネントツリーの境界を定義する。境界より下のコンポーネントはすべてClient Componentになる。可能な限りサーバー側に処理を寄せると高速化できる。