クライアントコンポーネント

クライアントコンポーネントを使用すると、サーバー側で事前レンダリングされたインタラクティブなUIを作成でき、クライアント側のJavaScriptを使用してブラウザで実行できます。

このページでは、クライアントコンポーネントの動作原理、レンダリング方法、および使用するタイミングについて説明します。

クライアントレンダリングの利点

クライアント側でレンダリングを行うことには、次のような利点があります:

  • インタラクティブ性: クライアントコンポーネントはstate、エフェクト、イベントリスナーを使用できるため、ユーザーに即座にフィードバックを提供し、UIを更新できます。
  • ブラウザAPI: クライアントコンポーネントは位置情報localStorageなどのブラウザAPIにアクセスできます。

Next.jsでのクライアントコンポーネントの使用

クライアントコンポーネントを使用するには、ファイルの先頭(インポート文の前)にReactの"use client"ディレクティブを追加します。

"use client"は、サーバーコンポーネントとクライアントコンポーネントモジュール間の境界を宣言するために使用されます。つまり、ファイルで"use client"を定義すると、そのファイルにインポートされる他のすべてのモジュール(子コンポーネントを含む)はクライアントバンドルの一部と見なされます。

'use client'

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}
'use client'

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

以下の図は、"use client"ディレクティブが定義されていない場合、ネストされたコンポーネント(toggle.js)でonClickuseStateを使用するとエラーが発生することを示しています。これは、App Routerのすべてのコンポーネントはデフォルトでサーバーコンポーネントであり、これらのAPIが利用できないためです。toggle.js"use client"ディレクティブを定義することで、これらのAPIが利用可能なクライアント境界に入るようにReactに指示できます。

Use Client Directive and Network Boundary

複数のuse clientエントリポイントの定義:

Reactコンポーネントツリー内に複数の"use client"エントリポイントを定義できます。これにより、アプリケーションを複数のクライアントバンドルに分割できます。

ただし、クライアント側でレンダリングする必要があるすべてのコンポーネントに"use client"を定義する必要はありません。一度境界を定義すると、その中にインポートされるすべての子コンポーネントとモジュールはクライアントバンドルの一部と見なされます。

クライアントコンポーネントのレンダリング方法

Next.jsでは、クライアントコンポーネントのレンダリング方法は、リクエストがフルページロード(アプリケーションへの初回訪問またはブラウザのリフレッシュによってトリガーされるページ再読み込み)か、それ以降のナビゲーションかによって異なります。

フルページロード

初期ページロードを最適化するために、Next.jsはReactのAPIを使用して、クライアントコンポーネントとサーバーコンポーネントの両方に対してサーバー上に静的HTMLプレビューをレンダリングします。つまり、ユーザーが初めてアプリケーションを訪問したとき、クライアントがクライアントコンポーネントのJavaScriptバンドルをダウンロード、解析、実行するのを待たずに、すぐにページのコンテンツが表示されます。

サーバー側では:

  1. Reactはサーバーコンポーネントを**React Server Component Payload (RSC Payload)**と呼ばれる特別なデータ形式にレンダリングします。これにはクライアントコンポーネントへの参照が含まれます。
  2. Next.jsはRSC PayloadとクライアントコンポーネントのJavaScript命令を使用して、サーバー上でルートのHTMLをレンダリングします。

その後、クライアント側では:

  1. HTMLは、ルートの高速な非インタラクティブな初期プレビューをすぐに表示するために使用されます。
  2. React Server Components Payloadは、クライアントコンポーネントとサーバーコンポーネントのツリーを調整し、DOMを更新するために使用されます。
  3. JavaScript命令は、クライアントコンポーネントをハイドレートし、UIをインタラクティブにするために使用されます。

ハイドレーションとは?

ハイドレーションは、静的なHTMLをインタラクティブにするためにDOMにイベントリスナーをアタッチするプロセスです。内部的には、ハイドレーションはReactのhydrateRoot APIを使用して行われます。

それ以降のナビゲーション

それ以降のナビゲーションでは、クライアントコンポーネントはサーバー側でレンダリングされたHTMLなしで、完全にクライアント側でレンダリングされます。

つまり、クライアントコンポーネントのJavaScriptバンドルがダウンロードされ、解析されます。バンドルの準備が整うと、ReactはRSC Payloadを使用してクライアントコンポーネントとサーバーコンポーネントのツリーを調整し、DOMを更新します。

サーバー環境に戻る

"use client"境界を宣言した後でも、サーバー環境に戻りたい場合があります。例えば、クライアントバンドルサイズを減らしたり、サーバー側でデータを取得したり、サーバー側でのみ利用可能なAPIを使用したりする場合です。

クライアントコンポーネント内に理論的にネストされている場合でも、クライアントコンポーネントとサーバーコンポーネントを交互に配置し、サーバーアクションを使用することで、コードをサーバー側に保持できます。詳細については、コンポジションパターンのページを参照してください。