React Server Componentsの正式サポート(2)
事前に描画されるサーバコンポーネント
サーバコンポーネントは、事前に「どこか」でレンダリングされるコンポーネントです。
「どこか」というのは漠然とした表現ですが、Reactでは決まっておらず、クライアントやSSR(Server Side Rendering)サーバーとも限りません。実際にはNext.jsなどのフレームワークや開発者自身が決定することになります。基本的にはビルド時にレンダリングされ、静的なHTMLページとしてクライアントに配信されます。動的なデータ読み込みが必要な場合はSSRサーバーでレンダリングすることもできます。
ブログ記事のように動的な読み込みが不要な場合は前者を、ユーザーのログイン状態などによって動的なデータ読み込みが必要な場合は後者を選択することになります。
サーバコンポーネントの例を見てみましょう。
export default async function Page() { const fruits = await loadFruitsFromCsv("./fruits.csv"); return ( <ul> {fruits.map((fruit) => ( <li key={fruit.id}>{fruit.name}</li> ))} </ul> ); }
この例では、loadFruitsFromCsv
関数でCSVファイルからフルーツのデータを読み込み、リスト表示しています。このコンポーネントが非同期関数になっていることに注目してください。これにより内部で直接await
が使え、直感的な記述で非同期的なデータ取得ができます。従来のNext.jsにおけるgetServerSideProps
を使った記述と比べると格段にシンプルになっています。
このサンプルでは、Next.jsを静的エクスポートモードにしていますので、ビルド時にデータが読み込まれてコンポーネントがレンダリングされ、静的なHTMLページとして出力されます。従って、Node.jsサーバーは必要なく、npm start
では単なるWebサーバーを動かしています。

フルーツの一覧が描画されていますが、これはクライアント側で描画されたものではなく、ビルド時にサーバで描画されたものです。ページのソースを表示してみると、フルーツ一覧の<li>
タグがHTMLとして出力されていることが確認できます(※)。
サーバコンポーネントの詳細については、先行記事 Next.jsの新常識「App Router」を学ぼう!を参照してください。
※厳密には、RSCはHTMLではなくRSC Payloadと呼ばれるJSON形式のデータを生成し、それをもとにHTMLがレンダリングされます。
サーバ側で実行されるサーバ関数
サーバ関数は、その名の通りサーバ側で実行される関数です。サーバ関数はクライアントコンポーネントからインポートして呼びだすこともできるのが特徴です。サーバ関数は、開発中にサーバアクションと呼ばれていたものと同じですが、リリースに際し、より汎用的な名前に変更されました。
サーバ関数はサーバコンポーネントもしくは専用のファイルで"use server"
でマークすることで定義します。リスト2ではサーバ関数をサーバコンポーネント内で定義しています。
import fs from "fs/promises"; export function ServerComponent() { // サーバコンポーネント async function myFirstServerFunction() { "use server"; // サーバ関数としてマーク console.log("myFirstServerFunction called!"); await fs.appendFile("log.txt", `myFirstServerFunction\n`); } console.log("Server Component rendered!"); return <button onClick={myFirstServerFunction}>Server Component</button>; }
関数内に"use server"
が記述されていることに注目してください。サーバサイドで動作する関数なので、fs/promises
というサーバ環境下(ここではNode.js)でしか機能しないモジュールを使用できています。
リスト3は、リスト2と同様の処理を別ファイルで定義したものです。
"use server"; import fs from "fs/promises"; export async function mySecondServerFunction() { // Server Function console.log("mySecondServerFunction called!"); await fs.appendFile("log.txt", `mySecondServerFunction\n`); }
ファイル先頭で"use server"
を記述すると、そのファイル内のすべての関数がサーバ関数として扱われます。このように別ファイルで定義しておくと、リスト4ようにクライアントコンポーネントからインポートして呼び出せるようになります。
"use client"; // クライアントコンポーネントとしてマーク import { mySecondServerFunction } from "./server-functions"; export function ClientComponent() { console.log("Client Component rendered!"); return <button onClick={mySecondServerFunction}>Client Component</button>; }
このサンプル02_react19-nextjs15-server-functions
を実行すると以下のような動作になります。いずれのボタンも関数自体はサーバ側で実行され、log.txt
にログが追記されます。

ClientComponent
はクライアント側でも描画されるため、ブラウザのコンソールにClient Component rendered!
が表示されています。Server Component
はサーバコンポーネントとしてビルド時にレンダリングされているため、実行時にはサーバ側のコンソールにも表示されません。
サーバ関数は第3回で説明したReact19の「アクション」から呼び出したり、<form>
アクションの関数として使用したりすることもできます。本記事では割愛しますが、実例はサンプルの03_react19-nextjs15-server-actions
を参照してください。