記事4でNext.jsのルーティングだけでアプリケーションは作成可能ですが、
Next.jsのServer コンポーネントと Client コンポーネントも知識程度に知っておくとよいので今回説明していきます。
記事見出し一覧
-
第1回【React】:React入門 — コンポーネントとJSXの基本
- Reactとは何か、コンポーネントについて学ぶ
-
第2回【React】:フック入門 — useState と useEffect
- useState と useEffectというReactの関数を学ぶ
-
第3回【React】:コンポーネント間で値を共有する方法
- 複数のコンポーネントを作ったときの値の共有方法を学ぶ
-
第4回【Next.js】:Next.jsの基本
- Next.jsとは、ルーティングについて学ぶ
-
第5回【Next.js】:(補足)サーバーコンポーネントとクライアントコンポーネント
- サーバーコンポーネントとクライアントコンポーネントについて学ぶ
第5回:(補足)サーバーコンポーネントとクライアントコンポーネント
アプリを作成していくと遭遇するエラー
恐らくアプリケーションを作っていくと
use clientをつけろというエラーに遭遇することになるかと思います。
作成するコンポーネントにはサーバーコンポーネントとクライアントコンポーネントというものがあり、
何も指定しないとデフォルトではサーバーコンポーネントとして扱われます。
これまで紹介したuseStateやuseEffectはクライアントコンポーネントでしか使えないため、
use clientをつけてクライアントコンポーネントとして定義しなければエラーになります。
とりあえずはuse clientばかりのコンポーネントになっても問題はないですが、
処理速度の改善やブラウザ側で処理するデータ量などの軽減も行えるため知識程度に紹介します。
サーバーコンポーネントとクライアントコンポーネントが分かれている理由
ユーザーが見るUI部分をクライアントコンポーネントとして定義し、
データ取得などの重い処理をサーバーコンポーネントとしてサーバーで行い、結果だけをブラウザに返すことで受け取るデータ量を軽減することができます。
これにより、先に表示はすぐに行い、時間のかかる処理はLoadingとしておいて結果が渡された時点で表示するというように、すべての処理が完了するまで画面が全く表示されない状況を回避できます。
コード例
コードを実行すると「ユーザー一覧へ」リンクを押すとユーザー情報をAPI(数秒かかる)から取得し表示します。
(画面自体はすぐ表示され、時間のかかる処理だけがLoading表示され用意できた段階で表示される)
クライアントコンポーネント(Client Component)
これまでの記事で説明してきたコンポーネント(useStateやuseEffectを使うもの)は、すべてクライアントコンポーネントです。
特徴
-
'use client'を定義したコンポーネント - ブラウザ上で実行されるUIや処理がある
- 以下のような機能をもつコンポーネントの場合がクライアントコンポーネントに該当する
- UIの設置(ボタン、テキストボックスなど)
- ユーザーの操作への応答(クリック、入力など)
- 状態管理(useState)
- 副作用の実行(useEffect)
- ブラウザのみの API(localStorageなど)
- 以下のような機能をもつコンポーネントの場合がクライアントコンポーネントに該当する
サーバーコンポーネント(Server Component)
特徴
- コンポーネント(jsxファイル)を作成するとデフォルトでサーバーコンポーネントとなる
- ビルド時もしくはサーバー側で一度だけ実行される
- 実行した結果が「RSC Payload」という特殊な形式に変換されてブラウザへ送られる
- データ処理はサーバー側で行うためブラウザ側では結果だけを送るなど、ブラウザ側で受け取るデータ量を減らすことができる
- サーバーコンポーネントはさらに2つに分けられる(※基本的にNext.jsが自動判断するため、最初は意識しなくてよい)
- 静的レンダリング(ビルド時に実行、レンダリングされる)
-
動的レンダリング(リクエスト時に実行、レンダリングされる)
- dynamic関数やcookies、searchParamsなどを使うと自動的に動的レンダリングになる。
下記を定義するとサーバーコンポーネントとして使えない
-
useState、useEffectなどのReact Hooksを使っている - イベントハンドラー(onClick等)を使っている
これらを使っている場合はuse clientをつけてクライアントコンポーネントで動かすしかない。
主な用途
- データベースへの直接アクセス
- データ取得(API実行)
- トークンなどの情報をブラウザ側に送らないので秘匿できる
- ファイルシステムへのアクセス
- サーバー専用のライブラリ使用
使い分けについて
筆者の所感だがuse clientをつけろとエラーになるのであればつけるぐらいで最初はよい気がする
APIの実行など外部通信や複雑な処理を行う部分を可能であれば別コンポーネントにしてサーバー側で実行させるのが良さそう
API呼び出しについて(useEffectとサーバーコンポーネント)
今回サーバーコンポーネントでAPI呼び出しを書くと説明しましたが、
以前useEffect内でAPIを呼び出すとも説明しました。
どちらを使うべきなのか?
ユーザー操作時にリクエストするのであればuseEffect(クライアントコンポーネント)を使う
最初の画面表示など(例:ニュースの一括取得など)でリクエストするのであればサーバーコンポーネントを使う。
使い分けについて
どちらを使うべきなのか?についてはAPIを呼び出すタイミングによって変わります。
サーバーコンポーネントでAPI呼び出し:
- ページを開いた時に一度だけデータが必要な場合
- APIキーやトークンなど秘密情報を使う場合
useEffectでAPI呼び出し(Client Component):
- ユーザーの操作に応じてデータを取得する場合
- 定期的に更新が必要な場合
コードの例
サーバーコンポーネントとuseEffectでそれぞれAPIを呼び出す例
- サーバーコンポーネント:APIを呼び出して一覧を取得
- useEffect:テキストボックスの内容を取得しAPI呼び出し
Suspenseについて(補足)
今回のコード例で<Suspense>というものを使っています。 これは非同期処理(API呼び出しなど)の読み込み中に、代わりの表示(「読み込み中・・・」など)をするための仕組みです。
使い方
<Suspense fallback={<div>読み込み中...</div>}>
<ProductList />
</Suspense>
- 子の要素(
<ProductList />)が読み込まれている間表示するものをfallbackで指定 - 子の要素(
<ProductList />)はasyncコンポーネント(非同期要素)である必要がある
コード例
import { Suspense } from 'react';
// サーバーコンポーネント(非同期)
async function ProductList() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
return (
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
export default function Page() {
return (
<div>
<h1>商品一覧 {/* すぐ表示される */}</h1>
<Suspense fallback={<div>読み込み中...</div>}>
{/* API完了後に表示される */}
<ProductList />
</Suspense>
</div>
);
}
参考
- https://ja.react.dev/reference/rsc/server-components
- https://nextjsjp.org/docs/app/getting-started/server-and-client-components
おわりに
以上でReactとNext.jsでアプリを作るうえで知っておいたほうが良いと思われる最低限の要素を網羅しました。
あくまで私個人の感覚としてここまで知っていればあとは適宜知っていけばよいのではと思っています。
ここまでが私が思うReact+Next.jsで最低限必要だと思われる知識についてでした。ここまで見ていただきありがとうございました!🙆♂️