はじめに
皆さんはNext.js
を使ってWeb開発をしていますか?私はNext.js
が好きでよく利用していますが、少しだけ不満に思う点があります。それはClient Components
に関することです。
Next.js
のApp Router
では作成したコンポーネントはデフォルトでサーバーのみでレンダリングをされるServer Components
となります。また、Server Components
登場以前からあるいわゆる「標準的な」Reactコンポーネント(Client Components
と呼ばれる)に切り替えて使うこともできます。
しかし、Client Components
という名前だとまるでクライアントのみでしかレンダリングされない見たいじゃないですか。Server Components
がサーバーでのみレンダリングされることから余計にそう思ってしまいます。
実際、私自身もNext.js
のApp Router
を学び始めの頃はずっとそう思っていました。元々Pages Router
からNext.js
を使い始め、App Router
に移行した際、しばらくの間、ドキュメントを読まずに「雰囲気」で使っていた(今もかもしれません…)のですが、ある日ドキュメントを読んで初めて気づきました。
個人的にはPages Router
からしっかり学んでいた方はClient Components
の誤解はないかもしれないですが、App Router
からやり始めた方や過去の自分みたいに全くドキュメントを見ない人は誤解してしまっているかもしれません。
ってことでドキュメント見ながら、Next.js
のレンダリングについてご紹介します。
私自身、まだWeb開発初心者なので、内容に誤りがあるかもしれません。その場合はぜひご指摘いただけると嬉しいです。
Client Components
Next.js
のレンダリング > クラアントコンポーネントを見ると、すぐにサーバー上でレンダリングされるということが書いてありました。
でも、事前レンダリングってなんだってなりますし、サーバー側でレンダリングして、どうやってインタラクティブなUIを実現するのでしょうか。もう少し読み進めてみます。
下のスクショではどのようにClient Components
がレンダリングされているかが書かれています。簡単に説明すると、サーバーで静的HTMLをレンダリングし、それがブラウザに表示された後、JSファイルをダウンロードしてインタラクティブなUIを実現している、という流れです。
スクショの最後にある「水分補給」とは、サーバーでレンダリングされたHTMLにクライアント側でインタラクティブ性を加えるプロセスのことを指します。この点については、akiさんの記事が視覚的に非常にわかりやすいです。
これによって、クライアント側でJSのロード、実行に時間がかかり、Reactコンポーネントがレンダリングされず、しばらく画面が白くなってしまう問題や、レンダリング前の要素のないHTMLがクローラーに渡されることでSEOの低迷してしまう問題を解消しています。
Server Components
Server Components
について詳しく説明すると本題から逸れてしまうので、ここでは簡単に触れるだけにします。当然ながら、Server Components
はサーバー側でレンダリングされます。
また、JSをロード・実行し、インタラクティブにするプロセスであるハイドレーションは行われていません。詳しいレンダリングの詳細に「水分補給」という言葉がありますが、これはクライアントコンポーネントの話をしています。
結論
Client Components
は、サーバー側で初期HTMLを生成し、クライアント側でハイドレーションを通じてインタラクティブ性を持つため、サーバーとクライアントの両方でレンダリングされます。一方、Server Components
はサーバー側でのみレンダリングされ、生成された静的HTMLがクライアントに送信されます。
Server Rendering | Client Rendering | |
---|---|---|
Client Components | ⭕️ | ⭕️ |
Server Components | ⭕️ | ❌ |
警告
たとえClient Components
でフックを使用せず、インタラクティブ性がゼロであっても、そのコンポーネントはクライアント側でのハイドレーションが行われます。
余談
じゃあ、なんて名前にするのがいいかという話なんですが、Standard Components
というのはどうでしょうか。これは「標準的な」Reactコンポーネントを表すのに適切な気がしています。これに伴って、ディレクティブも"use standard"
とかにしては良いのではないでしょうか。
"use standard";
import { useState } from "react";
export const Home = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>Counter Example</h1>
<p>Current Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
これはマジで余談なんで呼び飛ばしてもらって構いません。もしなにか良さげな名前あったらコメント欄とかで教えてほしいです!