Getting Started: React Essentials (Next.js公式ドキュメントより)

クライアントコンポーネントの下にサーバーコンポーネントを置く方法とそのための基礎知識。

ほぼ公式ドキュメントの翻訳とその解説です。

https://nextjs.org/docs/getting-started/react-essentials

まとめ

# Next.js 13のコンポーネント

Next.js 13から、基本的にすべてのコンポーネントがサーバーコンポーネントになります。
理由はそっちのほうが合理的だし便利だよね・・・だそうです。


クライアントコンポーネントとして使用する場合は、
 "use client"
というディレクティブを使用します。

ディレクティブというのは **ファイルの先頭** に記述し、そのファイル内のすべてのコンポーネントに適用されるルールのことです。

また通常必要ありませんが、サーバーコンポーネントとして明示的に宣言することも可能です。
その場合は
"use server"
というディレクティブを使用します。

このルールは、コンポーネント単位でも適用されます。

クライアントコンポーネントには、 "use client" ディレクティブをすべてのコンポーネントに付ける必要はありません。代わりに、ReactのTree構造の中で、グラフ理論における「頂点 (vertex)」にあたる部分で宣言することで、その下にあるコンポーネントはクライアントコンポーネントとして扱われるようになります。

# Next.js 12以前

これまではページ単位でデータをフェッチ（＝データの取得）していました。
クライアント用のコンポーネントがデフォルトで、
サーバーとクライアントのコンポーネントの区別も特についていませんでした。
同期でデータをフェッチしていました。

# Next.js 13移行

Next.js 13移行はコンポーネント単位でデータをフェッチすることができるようになりました。

RSC(React Server Component)とApp Routerが導入されました。
サーバー用のコンポーネントがデフォルトとなり、
ディレクティブを使うことでサーバーコンポーネントとクライアントコンポーネントを使い分けるようになりました。
RSCコンポーネントはサーバー上から非同期のfetch関数を使えるようになりました。
「並列」非同期のフェッチも可能です。


## hole
クライアントコンポーネントの下にサーバーコンポーネントを配置する場合は、propsとしてchildrenを渡すことができます。これを「hole」と呼びます。

サードパーティ製のコンポーネントも、Next.js 13のサーバーコンポーネントに対応していない場合は、一旦クライアントコンポーネントを作り、その下にサードパーティ製コンポーネントを配置することで、サーバーコンポーネントとして利用することができます



以下は翻訳と解説。

# ディレクティブとは？

ディレクティブは、プログラムやスクリプトにおいて、特定の処理を実行するための命令です。Next.js 13における "use client" ディレクティブは、サーバーコンポーネントをクライアントコンポーネントとして再利用するための命令です。具体的には、サーバーコンポーネントに "use client" ディレクティブを付けることで、そのコンポーネントをクライアントコンポーネントとして再利用することができます。


# サーバーコンポーネントとクライアントコンポーネントの公式ドキュメント

Next.js 13 公式ドキュメントとして

Getting Started: React Essentials | Next.js

https://nextjs.org/docs/getting-started/react-essentials

を読む

# メンタルモデルとは
人が物事を理解するために持つ心の中のモデルや概念のことを指します。つまり、人が物事を理解するために、自分なりのモデルや概念を作り上げているということです。

つまりNext.js13からはこんな独自の考え方を導入したので理解して使ってくださいねということでしょうか。

React Server Componentsが導入する新しいメンタルモデルとは、サーバーコンポーネントとクライアントコンポーネントを組み合わせて、ハイブリッドアプリケーションを構築するための考え方です。これまでのReactでは、クライアントコンポーネント側でのみコンポーネントがレンダリングされていましたが、React Server Componentsでは、サーバーコンポーネント側でもコンポーネントがレンダリングされるようになります。

この新しいメンタルモデルにより、開発者は、サーバーコンポーネントとクライアントコンポーネントを組み合わせて、より高速でスケーラブルなアプリケーションを構築することができます。また、サーバーコンポーネントにより、SEOの向上や、低速なネットワーク環境でも快適にアプリケーションを利用することができるようになります。

Next.js 13は

ページを小さなコンポーネントに分割すると、コンポーネントの大部分が非対話型であり、サーバーコンポーネント上でサーバーコンポーネントとしてレンダリングできることがわかります。インタラクティブ UI の小さな部分には、クライアントコンポーネントを散りばめることができます。これは Next.js のサーバーコンポーネントファーストのアプローチと一致しています。

# なぜサーバーコンポーネントなのか？

公式の説明を要約すると
そっちのほうが色々と便利だから

クライアントコンポーネントは
アプリケーションにクライアントコンポーネント側の対話性を追加できます。
Next.js では、サーバーコンポーネント上で事前レンダリングされ、クライアントコンポーネント上でハイドレートされます。

# ハイドレートとは？

Next.js 13における「ハイドレート」とは、サーバーコンポーネントサイドレンダリング（SSR）されたページを、クライアントコンポーネント側で再度レンダリングすることを指します。具体的には、サーバーコンポーネントサイドでレンダリングされたページを、クライアントコンポーネント側で再度レンダリングすることで、ページのインタラクティブ性を向上させることができます。

Next.js 13では、ハイドレートをより簡単に実現するために、新しいAPIが導入されました。このAPIを使用することで、サーバーコンポーネントサイドでレンダリングされたページを、クライアントコンポーネント側で再度レンダリングすることができます。また、このAPIを使用することで、ページの初期表示時に必要なデータをサーバーコンポーネントサイドで取得し、ページの読み込み時間を短縮することができます。

ハイドレートは、ユーザーがページを操作する際に、ページの再レンダリングを行うことで、よりスムーズなユーザーエクスペリエンスを提供することができます。また、SEOにも有効であり、サーバーコンポーネントサイドでレンダリングされたページを、クライアントコンポーネント側で再度レンダリングすることで、検索エンジンに対しても最適なページを提供することができます。

つまりサーバーコンポーネント側でフェッチしたデータでサーバーコンポーネントを作成し、そして、インタラクティブな要素を持ったコンポーネントをクライアントコンポーネント側でマージすることをハイドレートと言っているようです。


 "use client" ディレクティブ
サーバーコンポーネント モジュール グラフとクライアントコンポーネント モジュール グラフの間の境界を宣言するための規則です。


# サーバーコンポーネントモジュールグラフ内のコンポーネントとは

Next.js において、サーバーコンポーネントを含むモジュールの依存関係を表すグラフの中に存在するコンポーネントのことを指します。

サーバーコンポーネントとは、サーバーコンポーネントサイドでレンダリングされるコンポーネントのことであり、クライアントコンポーネント側でレンダリングされるコンポーネントとは異なります。サーバーコンポーネントは、サーバーコンポーネントサイドでレンダリングされるため、SEOの向上や、低速なネットワーク環境でも快適にアプリケーションを利用することができるようになります。

モジュールグラフとは、モジュール間の依存関係を表すグラフのことであり、Next.js においては、各ページやコンポーネントが依存するモジュールの関係を表すグラフが生成されます。

つまり、「サーバーコンポーネントモジュールグラフ内のコンポーネント」とは、サーバーコンポーネントを含むモジュールの依存関係を表すグラフの中に存在するコンポーネントのことを指します。このグラフを分析することで、サーバーコンポーネントを含むモジュールの依存関係を理解し、アプリケーションの最適化や、パフォーマンスの向上などを行うことができます。

 "use client" ディレクティブは、インポートの前にファイルの先頭に "use client" と記述する必要があります。また、すべてのファイルで "use client" を定義する必要はありません。クライアントコンポーネントの境界は、エントリーポイントで1回定義するだけで済みます。つまり、エントリーポイントで "use client" を定義することで、そのエントリーポイント以下のすべてのモジュールがクライアントコンポーネントとして扱われるようになります。

# エントリーポイントとは？

エントリーポイントはグラフ理論で言うところの「節」に相当します。
グラフ理論では、グラフを構成する要素を「節（vertex）」または「ノード（node）」と呼びます。エントリーポイントは、Next.jsのモジュールグラフにおいて、アプリケーションのエントリーポイントとなるモジュールを指します。つまり、エントリーポイントは、アプリケーションの起点となるモジュールであり、そのモジュールから他のモジュールへの依存関係が伸びていくグラフの「節」に相当します。


# コンポーネントのさまざまな使用例

サーバーコンポーネント
データを取得
バックエンド リソースに (直接) アクセスする
機密情報をサーバーコンポーネント上に保管 (アクセス トークン、API キーなど)
サーバーコンポーネントへの大きな依存関係を維持する / クライアントコンポーネント側の JavaScript を減らす

クライアントコンポーネント
インタラクティブ機能とイベント リスナー ( onClick()、onChange()、など)を追加
状態とライフサイクルの影響 ( useState()、useReducer()、useEffect()など)を使用するブラウザ専用 API を使用する
状態、効果、またはブラウザ専用 API に依存するカスタム フックを使用する

# パターン
パターン
アプリケーションのパフォーマンスを向上させるためには、可能な限りクライアントコンポーネントをコンポーネントツリーのリーフに移動することをお勧めします。

また、レイアウトをサーバーコンポーネントとして保持することも重要です。これにより、レイアウトのすべてのコンポーネントをクライアントコンポーネントに送信する必要がなくなります。


# クライアントコンポーネントおよびサーバーコンポーネントの構成

サーバーコンポーネントとクライアントコンポーネントは、同じコンポーネントツリー内で組み合わせることができます。

Reactは、次のようにレンダリングを処理します。

1. サーバーコンポーネントサイドでは、Reactはすべてのサーバーコンポーネントをレンダリングし、クライアントコンポーネントに送信する前に結果を生成します。この段階で、クライアントコンポーネント内にネストされたサーバーコンポーネントもレンダリングされます。

1. クライアントコンポーネントサイドでは、Reactはクライアントコンポーネントをレンダリングし、サーバーコンポーネントのレンダリング結果にスロットをレンダリングして、サーバーコンポーネントとクライアントコンポーネントで行われた作業をマージします。

1. サーバーコンポーネントがクライアントコンポーネント内にネストされている場合、レンダリングされたコンテンツはクライアントコンポーネント内に正しく配置されます。



# クライアントコンポーネント内にサーバーコンポーネントをネストする

上で概説したレンダリング フローを考慮すると、サーバーコンポーネントをクライアントコンポーネントにインポートする際には制限があります。これは、このアプローチでは追加のサーバーコンポーネント ラウンド トリップが必要になるためです。



# サーバーコンポーネント ラウンド トリップとは？

クライアントコンポーネントからサーバーコンポーネントにリクエストを送信し、サーバーコンポーネントがそのリクエストを処理してレスポンスを返すまでの時間を指します。つまり、サーバーコンポーネントをクライアントコンポーネントにインポートする場合、追加のサーバーコンポーネントリクエストが必要になるため、パフォーマンスが低下する可能性があるということです。



# サポートされていないパターン

サーバーコンポーネントをクライアントコンポーネントにインポートする



# 推奨パターン

サーバーコンポーネントを Props としてクライアントコンポーネントに渡す



## サーバーコンポーネントの「穴」

サーバーコンポーネントをクライアントコンポーネントに渡すための推奨パターンは、Reactのpropsを使用して、サーバーコンポーネントの「穴」をマークすることです。

サーバーコンポーネントはサーバーコンポーネント上でレンダリングされ、クライアントコンポーネントがクライアントコンポーネント上でレンダリングされると、サーバーコンポーネントのレンダリング結果が「穴」に埋め込まれます。

Reactのchildrenプロパティを使用して、「穴」を作成することが一般的なパターンです。これにより、を汎用的なchildrenプロパティを受け取るようにリファクタリングし、のインポートと明示的なネストを親コンポーネントに移動することができます。


### 穴とは

サーバーコンポーネントのレンダリング結果をクライアントコンポーネント内に埋め込むためのマークアップであり、Reactのchildrenプロパティを使用して作成することができます。この方法を使うことで、サーバーコンポーネントとクライアントコンポーネントを分離して、それぞれの役割に集中することができます。



```app/page.tsx
// This pattern works:
// You can pass a Server Component as a child or prop of a
// Client Component.
import ExampleClientComponent from './example-client-component'
import ExampleServerComponent from './example-server-component'

// Pages in Next.js are Server Components by default
export default function Page() {
  return (
    <ExampleClientComponent>
      <ExampleServerComponent />
    </ExampleClientComponent>
  )
}



```


この方法では、<ExampleクライアントコンポーネントComponent> と <ExampleサーバーコンポーネントComponent> のレンダリングが分離され、独立してレンダリングできます。
これは、サーバーコンポーネントがサーバーコンポーネント上でクライアントコンポーネントよりも前にレンダリングされるというサーバーコンポーネントの考え方と一致しています。



## ポイント

このパターンは、レイアウトやページでchildrenプロパティを使用しているため、追加のラッパーコンポーネントを作成する必要はありません。Reactコンポーネント（JSX）を他のコンポーネントに渡すことは新しい概念ではなく、常にReactのコンポジションモデルの一部でした。

このコンポジション戦略は、サーバーコンポーネントとクライアントコンポーネントにまたがって機能します。渡されたプロパティが何であるかを受け取るコンポーネントが知る必要はなく、渡されたプロパティがどこに配置されるべきかだけを担当します。

これにより、この場合はサーバーコンポーネント上で独立してレンダリングされ、クライアントコンポーネント上でレンダリングされるClient Componentよりもはるかに早くレンダリングされます。

また、同じ lifting content up 戦略は、親コンポーネントでの状態変更がインポートされたネストされた子コンポーネントの再レンダリングを回避するために使用されています。childrenプロパティに限らず、JSXを渡すために任意のプロパティを使用することができます。


### lifting content up 戦略とは？

Reactアプリケーションで、親コンポーネントの状態が変更された場合に、その状態変更が子コンポーネントに影響を与えることを避けるための戦略です。具体的には、子コンポーネントが必要とする状態を、親コンポーネントの状態として持ち上げ、propsとして子コンポーネントに渡すことで、子コンポーネントが必要な情報を取得できるようにします。

例えば、親コンポーネントがフォームを持っており、そのフォームに入力された値を子コンポーネントで表示する場合、フォームの入力値を親コンポーネントの状態として持ち上げ、propsとして子コンポーネントに渡すことで、子コンポーネントが入力値を表示できるようになります。

この戦略は、Reactアプリケーションでよく使用されるパターンの1つであり、コンポーネントの再レンダリングを最小限に抑えることができます。




## コンポジション戦略とは？

コンポジション戦略とは、Reactアプリケーションでコンポーネントを組み合わせる方法の1つで、コンポーネントを再利用可能で独立した部品として設計することを目的としています。この戦略では、小さなコンポーネントを組み合わせて大きなコンポーネントを作成することができます。

例えば、ボタンやテキストフィールドなどの小さなコンポーネントを組み合わせて、フォームやダイアログボックスなどの大きなコンポーネントを作成することができます。このように、小さなコンポーネントを再利用することで、コードの再利用性が高まり、保守性が向上します。

また、コンポジション戦略では、コンポーネントのpropsを使用して、コンポーネント間でデータを受け渡すことができます。これにより、コンポーネント間でのデータのやり取りが容易になり、コンポーネントの再利用性が高まります。





# サーバーコンポーネントからクライアントコンポーネントに props を渡す (シリアル化)

サーバーコンポーネントからクライアントコンポーネントに渡されるプロパティは、シリアライズ可能である必要があります。つまり、関数や日付などの値は、直接クライアントコンポーネントに渡すことはできません。


## ネットワークの境界線はどこにありますか？

アプリケーションのルーターでは、ネットワークの境界線はサーバーコンポーネントとクライアントコンポーネントの間にあります。これは、ページの場合と異なり、ページコンポーネントとgetStaticProps/getServerSidePropsの間に境界線があるためです。サーバーコンポーネントで取得されたデータは、クライアントコンポーネントに渡されない限り、ネットワークの境界線を越える必要がないため、シリアライズする必要はありません。





# クライアントコンポーネント・コンポーネントからサーバーコンポーネント専用コードを排除する（ポイズニング）

JavaScriptモジュールはサーバーコンポーネントとクライアントコンポーネントの両方で共有することができるため、サーバーコンポーネント上でのみ実行されることを意図していたコードが、クライアントコンポーネントにこっそり入り込んでしまう可能性があります。

例えば、次のようなデータ・フェッチ関数があります：

```lib/data.ts
export async function getData() {
  const res = await fetch('https://external-service.com/data', {
    headers: {
      authorization: process.env.API_KEY,
    },
  })

  return res.json()
}



```



一見すると、getDataはサーバーコンポーネントとクライアントコンポーネントの両方で動作するように見えます。しかし、環境変数API_KEYの前にNEXT_PUBLICが付けられていないため、サーバーコンポーネントでのみアクセスできるプライベート変数になっています。Next.jsでは、セキュアな情報の漏えいを防ぐため、クライアントコンポーネントコードではプライベートな環境変数を空文字列に置き換えています。

その結果、クライアントコンポーネントでgetData()をインポートして実行しても、期待どおりに動作しません。また、この変数をパブリックにすれば、クライアントコンポーネント上で関数は動作しますが、機密情報が漏れることになります。

そのため、この関数はサーバーコンポーネント上でのみ実行されることを想定して書かれています。

## server-only パッケージ
このような意図しないクライアントコンポーネントでのサーバーコンポーネントコードの利用を防ぐために、server-only パッケージを使用することで、他の開発者が誤ってこれらのモジュールをクライアントコンポーネントにインポートしてしまった場合に、ビルド時にエラーを表示することができます。

サーバーコンポーネント専用パッケージを使うには、まずパッケージをインストールしてください：

npm install server-only

次に、サーバーコンポーネント専用コードを含む任意のモジュールにパッケージをインポートします。


```lib/data.js
import 'server-only'

export async function getData() {
  const res = await fetch('https://external-service.com/data', {
    headers: {
      authorization: process.env.API_KEY,
    },
  })

  return res.json()
}



```

getData()をインポートする任意のクライアントコンポーネントは、このモジュールがサーバーコンポーネント上でのみ使用できることを説明するビルド時エラーを受け取ります。これにより、クライアントコンポーネントで誤ってサーバーコンポーネントコードを実行することが防止されます。

対応するパッケージclient-onlyは、windowオブジェクトにアクセスするなど、クライアントコンポーネント側でのみ実行されるコードを含むモジュールをマークするために使用できます。このパッケージを使用することで、クライアントコンポーネントコードとサーバーコンポーネントコードを明確に区別し、アプリケーションのセキュリティを向上させることができます。





# Data Fetching

クライアントコンポーネント・コンポーネントでデータをフェッチすることは可能ですが、クライアントコンポーネントでデータをフェッチする特別な理由がない限り、サーバーコンポーネント・コンポーネントでデータをフェッチすることをお勧めします。

データ取得をサーバーコンポーネントに移すことで、パフォーマンスとユーザーエクスペリエンスが向上します。




# Third-party packages

現状、Next.js13の新しいメンタルモデルに対応するため、エコシステム内のサードパーティパッケージは、useState、useEffect、createContextなどのクライアントコンポーネント専用機能を使用するコンポーネントに "use client" ディレクティブを追加し始めています。

これらのサードパーティコンポーネントは、クライアントコンポーネント内では "use client" ディレクティブがあるため、期待どおりに動作します。

しかし、クライアントコンポーネントを使用する多くのnpmパッケージのコンポーネントには、 "use client" ディレクティブに対応してないのが多くあります。

その場合はClient Componentでラップして使用するようにすると使えるようになります。

例

```app/carousel.tsx
'use client'

import { Carousel } from 'acme-carousel'

export default Carousel


```

↑このようにクライアントコンポーネントでラップすることにより、
↓このようにサードパーティ製のコンポーネントを使うことができるようになります。

```app/page.tsx
import Carousel from './carousel'

export default function Page() {
  return (
    <div>
      <p>View pictures</p>

      {/*  Works, since Carousel is a Client Component */}
      <Carousel />
    </div>
  )
}


```

クライアントコンポーネント内で使用すると期待どおりに動作します。

これはグラフの節で "use client" ディレクティブを宣言してクライアントコンポーネントにし、それより下のコンポーネントはすべてクライアントコンポーネントになるというルールを利用しています。

このコンポーネントは、このようにクライアントコンポーネントより下で使用すると期待通りに動作します。これはグラフの節で "use client" というディレクティブを宣言してクライアントコンポーネントにし、それより下にあるすべてのコンポーネントがクライアントコンポーネントになるというルールを利用しています。



----------------------------------------

# 基本ルール

ルール１
サーバーコンポーネントの下にクライアントコンポーネントは置ける
ルール２
クライアントコンポーネントの下にサーバーコンポーネントは置けない

でもクライアントコンポーネントの下にサーバーコンポーネントを置きたい場合がある
その抜け道をつくりだすのが
Composition パターン

# Composition パターンとは？

Composition パターンは、オブジェクト指向プログラミングにおいて、複数のオブジェクトを組み合わせて新しいオブジェクトを作成するためのパターンです。このパターンでは、オブジェクトを木構造のような階層構造に組み合わせることができます。

具体的には、あるオブジェクトが他のオブジェクトを持つことができます。この場合、持たれるオブジェクトは「部品」と呼ばれます。部品は、単体で機能することができますが、複数の部品を組み合わせることで、より複雑な機能を持つオブジェクトを作成することができます。

Composition パターンは、以下のような特徴を持ちます。

部品となるオブジェクトは、単体で機能することができます。
部品となるオブジェクトは、他のオブジェクトに組み込まれることができます。
組み込まれたオブジェクトは、そのままの形で機能することができます。
組み込まれたオブジェクトは、親オブジェクトから制御されることができます。
Composition パターンは、オブジェクト指向プログラミングにおいて、再利用性や拡張性を高めるために使用されます。例えば、GUIアプリケーションにおいて、ウィンドウやボタンなどの部品を組み合わせて、複雑な画面を作成することができます。また、グラフィックスエンジンにおいて、図形やテクスチャなどの部品を組み合わせて、複雑な画像を作成することができます。



# 参考

公式ドキュメント
Getting Started: React Essentials | Next.js

https://nextjs.org/docs/getting-started/react-essentials


Next.js 13で実現されるServer Componentについて調べてみた - Qiita

https://qiita.com/mjm2kt/items/82bc7cd346701937f4f9

【React Server Component】Server を Client の内側に注入できる Composition の力 - Qiita

https://qiita.com/honey32/items/bc24d8c0ea3d096ff956