React Server Componentsを理解する:次世代のReactアーキテクチャ
5分で読む
Tech Blog Admin

広告スペース
Slot: article-top
Format: horizontal
本番環境でGoogle AdSenseが表示されます
React Server Componentsとは
React Server Components(RSC)は、サーバー側でレンダリングされ、クライアントに送信されるJavaScriptバンドルサイズを削減する革新的な技術です。
従来のSSRとRSCの違い
従来のSSR
// 全てのコンポーネントがクライアントでもハイドレーションされる
function TraditionalSSR() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
React Server Components
// Server Component(デフォルト)
async function PostList() {
// サーバー側でのみ実行
const posts = await db.posts.findMany();
return (
<div>
{posts.map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
);
}
// Client Component
'use client'
function LikeButton({ postId }: { postId: string }) {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? '❤️' : '🤍'}
</button>
);
}
RSCの主なメリット
1. バンドルサイズの削減
// Server Component - クライアントバンドルに含まれない
import { marked } from 'marked'; // 重いライブラリ
import hljs from 'highlight.js';
async function ArticleContent({ markdown }: { markdown: string }) {
const html = marked(markdown, {
highlight: (code, lang) => {
return hljs.highlight(code, { language: lang }).value;
}
});
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
2. データフェッチングの簡略化
// コンポーネント内で直接データフェッチ
async function UserProfile({ userId }: { userId: string }) {
const user = await fetch(`/api/users/${userId}`).then(r => r.json());
const posts = await fetch(`/api/users/${userId}/posts`).then(r => r.json());
return (
<div>
<h1>{user.name}</h1>
<PostList posts={posts} />
</div>
);
}
3. 自動的なコード分割
// 動的インポートが自動的に処理される
async function Dashboard() {
const AdminPanel = await import('./AdminPanel');
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Loading />}>
<AdminPanel.default />
</Suspense>
</div>
);
}
実践的な実装パターン
パターン1: データフェッチングの最適化
// app/posts/[id]/page.tsx
async function PostPage({ params }: { params: { id: string } }) {
// 並列データフェッチング
const [post, comments] = await Promise.all([
getPost(params.id),
getComments(params.id)
]);
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
<Suspense fallback={<CommentsLoading />}>
<Comments comments={comments} />
</Suspense>
</article>
);
}
パターン2: 混在コンポーネント設計
// Server Component
async function ProductPage({ id }: { id: string }) {
const product = await getProduct(id);
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<ProductImage src={product.image} />
{/* Client Componentを含む */}
<AddToCartButton productId={id} />
</div>
);
}
// Client Component
'use client'
function AddToCartButton({ productId }: { productId: string }) {
const [isAdding, setIsAdding] = useState(false);
const handleAddToCart = async () => {
setIsAdding(true);
await addToCart(productId);
setIsAdding(false);
};
return (
<button onClick={handleAddToCart} disabled={isAdding}>
{isAdding ? '追加中...' : 'カートに追加'}
</button>
);
}
ストリーミングとSuspense
// レイアウトでの活用
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<Suspense fallback={<HeaderSkeleton />}>
<Header />
</Suspense>
<main>{children}</main>
<Suspense fallback={<FooterSkeleton />}>
<Footer />
</Suspense>
</div>
);
}
// 段階的なレンダリング
async function SlowComponent() {
await new Promise(resolve => setTimeout(resolve, 3000));
return <div>遅いコンポーネント</div>;
}
function Page() {
return (
<>
<FastComponent />
<Suspense fallback={<Loading />}>
<SlowComponent />
</Suspense>
</>
);
}
エラーハンドリング
// error.tsx
'use client'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div className="error-container">
<h2>エラーが発生しました</h2>
<p>{error.message}</p>
<button onClick={reset}>再試行</button>
</div>
);
}
パフォーマンス最適化のコツ
1. 適切なコンポーネント分割
// ❌ 悪い例:全体がClient Component
'use client'
function ProductPage() {
const [quantity, setQuantity] = useState(1);
// 静的なコンテンツも含まれる
return <div>...</div>;
}
// ✅ 良い例:必要な部分のみClient Component
function ProductPage() {
return (
<div>
<ProductInfo /> {/* Server Component */}
<QuantitySelector /> {/* Client Component */}
</div>
);
}
2. データの事前フェッチ
// Parallel data fetching
async function Page() {
// データフェッチを開始(awaitしない)
const userPromise = getUser();
const postsPromise = getPosts();
return (
<div>
<Suspense fallback={<UserSkeleton />}>
<UserInfo userPromise={userPromise} />
</Suspense>
<Suspense fallback={<PostsSkeleton />}>
<PostList postsPromise={postsPromise} />
</Suspense>
</div>
);
}
まとめ
React Server Componentsは、パフォーマンスとDXを両立する革新的な技術です。適切に活用することで、高速でSEOフレンドリーなアプリケーションを構築できます。
Next.js 13以降のApp Routerと組み合わせることで、その真価を発揮します。ぜひプロジェクトで活用してみてください!
広告スペース
Slot: article-bottom
Format: rectangle
本番環境でGoogle AdSenseが表示されます