コンテンツにスキップ

10

サーバーコンポーネントとクライアントコンポーネント

サーバーコンポーネントとクライアントコンポーネントの仕組みを理解するには、Web の 2 つの基本概念を理解しておくと役立ちます。

  • アプリケーションコードを実行できる環境: サーバーとクライアント。
  • サーバーコードとクライアントコードを分離するネットワーク境界

サーバー環境とクライアント環境

Web アプリケーションのコンテキストでは

Diagram showing a browser on the left and a server on the right, separated by a network boundary.
  • クライアントとは、アプリケーションコードのリクエストをサーバーに送信する、ユーザーのデバイス上のブラウザのことです。そして、サーバーから受信したレスポンスを、ユーザーが操作できるインターフェースに変換します。
  • サーバーとは、アプリケーションコードを保存し、クライアントからのリクエストを受信し、何らかの計算を行い、適切なレスポンスを返すデータセンター内のコンピュータのことです。

各環境には、それぞれ独自の機能と制約があります。たとえば、レンダリングとデータフェッチをサーバーに移動することで、クライアントに送信されるコードの量を削減でき、アプリケーションのパフォーマンスを向上させることができます。ただし、前述したように、UI をインタラクティブにするには、クライアントで DOM を更新する必要があります。

そのため、サーバーとクライアント用に記述するコードは、必ずしも同じではありません。特定の操作 (例: データフェッチやユーザー状態の管理) は、一方の環境の方が適しています。

ネットワーク境界

ネットワーク境界とは、異なる環境を分離する概念的な線です。

React では、コンポーネントツリー内のどこにネットワーク境界を配置するかを選択します。たとえば、サーバー上でデータを取得し、ユーザーの投稿をレンダリングし (サーバーコンポーネントを使用)、クライアント上で各投稿のインタラクティブな LikeButton をレンダリングできます (クライアントコンポーネントを使用)。

同様に、サーバー上でレンダリングされ、ページ間で共有される Nav コンポーネントを作成できますが、リンクのアクティブ状態を表示するには、クライアント上で Links のリストをレンダリングできます。

A component tree showing a layout that has 3 components as its children: Nav, Page, and Footer. The page component has 2 children: Posts and LikeButton. The Posts component is rendered on the server, and the LikeButton component is rendered on the client.

背後では、コンポーネントは 2 つのモジュールグラフに分割されます。サーバーモジュールグラフ (またはツリー) には、サーバー上でレンダリングされるすべてのサーバーコンポーネントが含まれ、クライアントモジュールグラフ (またはツリー) には、すべてのクライアントコンポーネントが含まれます。

サーバーコンポーネントがレンダリングされた後、React Server Component Payload (RSC) と呼ばれる特別なデータ形式がクライアントに送信されます。RSC ペイロードには以下が含まれます。

  1. サーバーコンポーネントのレンダリング結果。
  2. クライアントコンポーネントをレンダリングする場所のプレースホルダー (またはホール) と、それらの JavaScript ファイルへの参照。

React はこの情報を使用して、サーバーコンポーネントとクライアントコンポーネントを統合し、クライアントの DOM を更新します。

これがどのように機能するかを見てみましょう。

クライアントコンポーネントの使用

前のチャプターで学んだように、Next.js はデフォルトでサーバーコンポーネントを使用します。これはアプリケーションのパフォーマンスを向上させるためであり、採用するために追加の手順を実行する必要はありません。

ブラウザのエラーを振り返ると、Next.js はサーバーコンポーネント内で useState を使用しようとしていることを警告しています。インタラクティブな「いいね」ボタンをクライアントコンポーネントに移動することで、これを修正できます。

LikeButton コンポーネントをエクスポートする like-button.js という新しいファイルを app フォルダ内に作成します。

/app/like-button.js
export default function LikeButton() {}

<button> 要素と handleClick() 関数を page.js から新しい LikeButton コンポーネントに移動します。

/app/like-button.js
export default function LikeButton() {
  function handleClick() {
    setLikes(likes + 1);
  }
 
  return <button onClick={handleClick}>Like ({likes})</button>;
}

次に、likes 状態とインポートを移動します。

/app/like-button.js
import { useState } from 'react';
 
export default function LikeButton() {
  const [likes, setLikes] = useState(0);
 
  function handleClick() {
    setLikes(likes + 1);
  }
 
  return <button onClick={handleClick}>Like ({likes})</button>;
}

次に、LikeButton をクライアントコンポーネントにするには、ファイルの先頭に React の 'use client' ディレクティブを追加します。これは、React に対して、コンポーネントをクライアントでレンダリングするように指示します。

/app/like-button.js
'use client';
 
import { useState } from 'react';
 
export default function LikeButton() {
  const [likes, setLikes] = useState(0);
 
  function handleClick() {
    setLikes(likes + 1);
  }
 
  return <button onClick={handleClick}>Like ({likes})</button>;
}

page.js ファイルに戻り、LikeButton コンポーネントをページにインポートします。

/app/page.js
import LikeButton from './like-button';
 
function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}
 
export default function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];
 
  return (
    <div>
      <Header title="Develop. Preview. Ship." />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>
      <LikeButton />
    </div>
  );
}

両方のファイルを保存して、ブラウザでアプリを表示します。エラーがなくなったら、変更を加えて保存すると、ブラウザが自動的に更新されて変更が反映されるはずです。

この機能は高速リフレッシュと呼ばれます。行った編集に関する即座のフィードバックを提供し、Next.js にプリコンフィグされています。

まとめ

要約すると、サーバー環境とクライアント環境、およびそれぞれをいつ使用するかについて学びました。また、Next.js はデフォルトで React サーバーコンポーネントを使用してパフォーマンスを向上させること、および UI の小さな部分をインタラクティブにするためにクライアントコンポーネントをどのようにオプトインできるかについても学びました。

追加の参考文献

サーバーコンポーネントとクライアントコンポーネントについては、さらに学ぶべきことがたくさんあります。追加のリソースを以下に示します。

チャプターを完了しました10

サーバーコンポーネントとクライアントコンポーネントの使用方法を学びました。

次へ

11: 次の手順

次は何ですか?