Next.jsのClientコンポーネントなのにSSRされてる?を理解する

2025/04/10
最近、Next.jsのApp Routerで開発を進めている中で、ある挙動に違和感を持った方もいるのではないでしょうか?
「
'use client'
って書いてるのに、なんかサーバーでレンダリングされてるっぽい……?」
実はこれ、Next.jsのApp RouterではクライアントコンポーネントでもHTMLはサーバーで生成されるという仕組みによるものです。
今回はこの挙動を整理し、「クライアントコンポーネント=CSR(Client Side Rendering)」と思い込んでいると見誤りやすい点を、実例とともにわかりやすく解説します。
Clientコンポーネントとは?
まず基本を整理します。
'use client'
が先頭に書かれたファイルはクライアントコンポーネントになります。Reactのhooks(
useState
,useEffect
など)やイベントハンドラ(onClick
など)を使う場合、'use client'
が必要です。ここで誤解されがちなのが、クライアントコンポーネント=CSRになるという思い込みです。
実際には、App Routerでの挙動はそれとは異なります。
App Routerの基本:まずはHTMLがサーバーで生成される
Next.js 13以降のapp/
ディレクトリでは、ページの初期HTMLは常にサーバーで生成(SSRまたはSSG)されます。
これにはクライアントコンポーネントも含まれており、サーバーでHTMLを生成した後にクライアント側でhydrate(復元)される流れになります。
つまり:
'use client'
があっても、HTML自体はサーバーから送られてくる
実際に検証してみる
次のようなコードをapp/page.tsx
に書いてみましょう。
'use client';
export default function Page() {
console.log(
'Rendering Client Component'
);
return (
<div>Hello from client</div>
);
}
このとき、console.log()
の出力がサーバー側にも出ることに驚いた方もいるかもしれません。
クライアント用JSバンドルとして動くだけでなく、最初の描画はサーバー上でも実行されるのです。
ただし、
useEffect()
などはサーバーでは動かず、クライアント側でのみ実行されます。
なぜそんな挙動になるのか?
これは、**React Server Components(RSC)**の影響によるものです。
App Routerは、できるだけサーバー側でUIを構築して軽いHTMLを返し、クライアントへのJS転送を最小限にする設計になっています。
そのため、Clientコンポーネントも含めて「まずはサーバーでHTMLを生成し、必要なJSだけあとから読み込む」というスタイルになります。
この挙動を正しく理解しておかないと、以下のような誤解をしがちです:
'use client'
ならすべてCSRされる → ✕SSRしたいならServerコンポーネントでなければいけない → ✕(ClientでもSSRされる)
結局どう考えればいいのか?
Clientコンポーネントは「ブラウザでJSとして動く」という意味であって、レンダリング方法を決めるものではない。
App Routerでは、HTMLは基本的にサーバーで生成される(SSR/SSG)。
CSRとClient Componentは別モノとして理解するのが正しいです。
✅ 「クライアントコンポーネント = CSR」ではない。
おわりに
Next.jsのApp Routerは柔軟で強力な反面、挙動がややわかりにくい部分もあります。
今回は「クライアントコンポーネントなのにSSRされているように見える」という点に絞って解説しました。
今後は use client
の制限や、Server Componentとの組み合わせ方など、さらに掘り下げていけたらと思います。
読んでいただきありがとうございました!