Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
サーバー/クライアント境界、RSCペイロードストリーミング、バンドルなしのサーバーレンダリング。
React Server Components(RSC)はサーバー上でのみ実行されるコンポーネントです — ブラウザには決して送信されません。クライアントのバンドルコストゼロで、データベース、ファイルシステム、サーバー専用のシークレットに直接アクセスできます。RSCの出力はHTMLではなく、クライアントのReactがサーバーコードを再実行せずにコンポーネントツリーを再構築するために使用する特別なワイヤーフォーマット(RSCペイロード)です。
ページがロードされると、サーバーはServer Componentsを実行し、非同期データベースクエリ、ファイル読み取り、またはAPI呼び出しを直接実行します。出力はHTMLではなく、カスタムストリーミングフォーマットのシリアライズされたReactエレメントツリー(RSCペイロード)です。
サーバーがClient Component('use client'でマーク)に遭遇すると、それをレンダリングしません。代わりに、ペイロードにコンポーネントのモジュールURLとpropsを含むCLIENT_REFERENCEプレースホルダーを挿入します。クライアントはブラウザでClient Componentを実行することでこれらの穴を埋めます。
サーバーは各非同期操作が完了するたびにRSCペイロードをストリームします。クライアントのReactランタイムはチャンクを受信し、段階的にコンポーネントツリーを構築します — まずServer Componentの出力、次にClient Componentのシェル、そしてハイドレーション。
クライアントのReactはストリームされたRSCペイロードを受け取り、完全なコンポーネントツリーを再構築するために使用します。ハイドレートされる(イベントリスナーが付与される)のはClient Componentsのみです。Server Componentの出力はすでに最終的なものです — クライアントで再実行されません。
'use server'でマークされた関数はServer Actionsになります — クライアントが通常の非同期関数のように呼び出せるRPCスタイルの関数です。内部では、ReactはエンコードされたargumentとともにサーバーにPOSTリクエストを送信し、新しいRSCペイロードをストリームで返します。
モジュールとそのすべてのインポートをClient Componentsとしてマークするファイルレベルのディレクティブ。クライアントバウンダリを作成します — すべてのエクスポートでhooks、イベントハンドラー、ブラウザAPIを使用できます。
関数をServer Actionとしてマークします。ネットワークリクエストを通じてClient Componentsから呼び出せます。関数はフルサーバーサイドアクセスを持ってサーバー上で実行されます。
サーバーでレンダリングされたコンポーネントツリーを記述するコンパクトなストリーミングJSON形式。Client Componentsが入るべき場所にCLIENT_REFERENCEの穴を含みます。HTMLではありません。
Server Componentsはクライアントのバンドルに一切含まれません。500KBのMarkdownパーサーをインポートするServer Componentはクライアントに0バイトを追加します。
'use client'または'use server'のないコンポーネントは両方のコンテキストで使用できます。Server Componentからインポートされるとサーバーで実行され、Client Componentからインポートされるとクライアントで実行されます。
1// ServerComponent.tsx — runs ONLY on server2// No bundle cost, can use async/await, access DB directly3async function ProductPage({ id }) {4 const product = await db.products.findById(id); // direct DB access!56 return (7 <div>8 <h1>{product.name}</h1>9 {/* Pass server data to a client component */}10 <AddToCartButton productId={product.id} price={product.price} />11 </div>12 );13}1415// AddToCartButton.tsx — runs on client (needs onClick)16'use client';17function AddToCartButton({ productId, price }) {18 const [added, setAdded] = useState(false);1920 return (21 <button onClick={() => {22 addToCart(productId);23 setAdded(true);24 }}>25 {added ? 'Added!' : `Add for $${price}`}26 </button>27 );28}
Server Componentsはパフォーマンスの方程式を根本的に変えます。以前は、データをフェッチするコンポーネントはフェッチライブラリ、データ変換ロジック、レンダリングコードをクライアントに送信する必要がありました。RSCでは、それらすべてがサーバーに留まります。クライアントは最終的なレンダリング出力とインタラクティブなアイランド(Client Components)のみを受け取ります。これにより、バンドルサイズが大幅に小さくなり、Time-to-Interactiveが向上します。
A product detail page needs to show: product info (from DB), reviews (from API), and an interactive 'Add to Cart' button. Traditional approach: fetch all data client-side with useEffect → loading spinners → hydration overhead.
Client-side fetching means: ship the fetch logic in the bundle → render loading state → make API calls from the browser → parse responses → re-render with data. The user sees a spinner, the bundle includes API client code, and there's a waterfall: page loads → JS executes → fetch starts → data arrives.
Make ProductPage and Reviews as Server Components (the default in Next.js App Router). They fetch data on the server with direct DB/API access and send pre-rendered HTML. Only AddToCartButton is a Client Component (marked with 'use client') because it needs onClick. Zero API client code in the bundle.
Takeaway: Server Components eliminate the request waterfall by moving data fetching to the server. Only interactive components (buttons, forms, animations) need to be Client Components. This pattern typically reduces bundle size by 30-50% and eliminates loading spinners for initial data.
You're building a blog post page. It has a header (static), article body (static with syntax-highlighted code), a comment section (interactive — like/reply buttons), and a share widget (interactive — copy link, social share).
New developers often mark the entire page as 'use client' because ONE component needs interactivity. This sends the entire page's JavaScript to the browser — syntax highlighting library, markdown parser, etc. — even though 80% of the page is static content.
Keep the page as a Server Component (default). Only wrap Comment and ShareWidget with 'use client'. The header, article body, and syntax highlighting render on the server and send zero JavaScript. The client only receives the small interactive components. Think of the boundary as: 'What needs browser APIs (state, effects, event handlers)?'
Takeaway: Push the 'use client' boundary as far DOWN the tree as possible. The rule: a component should be a Client Component only if it directly uses useState, useEffect, onClick, or browser-only APIs. Everything else should stay as a Server Component for zero bundle cost.