【Next.js】’use client’はいつ・どこに書く?使い分けの判断基準

JavaScript

こんにちは、かつコーチです。

前回はServer Componentsとは何か、これまでのReactとの一番の違いを解説しました。

「インタラクティブな部分は "use client" を使ってClient Componentに切り出す」というところまでは理解できても、実際にどのファイルに、どの粒度で書けばいいか迷う方は多いです。

今回は、"use client" をいつ・どこに書くべきか、判断基準を具体的に解説します。

‘use client’とは?

ファイルの境界を宣言するディレクティブ

"use client"とは、ファイルの一番上に書くディレクティブ(指示文)で、「このファイルとその中で使うコンポーネントはClient Componentとして扱ってください」とNext.jsに伝えるものです。

"use client";

import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

なぜそれが必要なのか

前回解説した通り、useStateonClick はブラウザ側でしか動かないため、それらを使うファイルには明示的に「ここから先はブラウザで動きます」という境界を宣言する必要があります。

この境界がないと、Next.jsはどこまでをサーバー用のバンドルに含め、どこからをブラウザ用のJavaScriptとして出力すればいいか判断できません。

基本の書き方

手順1:’use client’はファイルの一番上に書く

// components/LikeButton.tsx
"use client";

import { useState } from "react";

export function LikeButton() {
  const [liked, setLiked] = useState(false);

  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? "いいね済み" : "いいね"}
    </button>
  );
}

import文よりも上に書く必要があり、コメント以外の何かがその前にあるとエラーになります。

手順2:’use client’は「そのファイルからimportされる先」に伝播する

"use client" を書いたファイルからimportされたコンポーネントは、たとえそのファイル自体に "use client" がなくても、Client Componentとして扱われます。

// components/LikeButton.tsx
"use client";

import { Icon } from "./Icon"; // Iconには"use client"がなくてもClientとして動く

export function LikeButton() {
  // ...
}

一方、Client Componentの子要素として渡されたServer Componentは、Server Componentのまま維持されます。

// app/page.tsx(Server Component)
import { Modal } from "./Modal"; // Client Component
import { ServerChart } from "./ServerChart"; // Server Component

export default function Page() {
  return (
    <Modal>
      <ServerChart /> {/* childrenとして渡すとServerのまま */}
    </Modal>
  );
}

判断基準:どこに’use client’を書くべきか

以下のいずれかに当てはまる場合のみ、そのコンポーネントに "use client" を付けます。

  • useStateuseEffectuseContext などのHookを使う
  • onClickonChange などのイベントハンドラを使う
  • windowlocalStorage などブラウザ専用APIを使う
  • サードパーティ製のクライアント向けライブラリを使う

逆に言えば、これらに該当しない限り、"use client" は不要です。

つまずきやすい設定・注意点

"use client" は「そこから下の全てをブラウザ用JavaScriptに含める」宣言なので、ファイルツリーの上のほう(layout.tsx など)に書くと、影響範囲が意図せず広がります。

よくあるつまずきポイント・エラー対処

一次情報:layout.tsxに’use client’を書いてバンドルが膨らんだ話

私が最初に「エラーが出るのが面倒だから」という理由で、app/layout.tsx にまるごと "use client" を書いてしまったことがあります。

❌ Before:layout.tsxに’use client’を書く

// app/layout.tsx
"use client";

import { Header } from "./Header";
import { Footer } from "./Footer";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        <Header />
        {children}
        <Footer />
      </body>
    </html>
  );
}

一見エラーは出ず動いているように見えたのですが、ビルド後の出力を見て「クライアント側JavaScriptのサイズが想定より大きい」ことに気づきました。

layout.tsx はほぼ全ページで使われる共通の入口のため、ここに "use client" を書くと、配下の多くのコンポーネントが実質的にClient Component扱いになってしまいます。

✅ After:インタラクティブな部分だけを切り出す

// app/layout.tsx("use client"なし、Server Componentのまま)
import { Header } from "./Header";
import { Footer } from "./Footer";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        <Header />
        {children}
        <Footer />
      </body>
    </html>
  );
}
// app/Header.tsx
"use client";

import { useState } from "react";

export function Header() {
  const [open, setOpen] = useState(false);
  // ハンバーガーメニューの開閉だけがuse clientの理由
  return (
    <header>
      <button onClick={() => setOpen(!open)}>メニュー</button>
      {open && <nav>...</nav>}
    </header>
  );
}

layout.tsx 自体は "use client" なしのServer Componentに戻し、実際に useState が必要な Header.tsx だけに "use client" を付け直すことで、バンドルサイズを大幅に減らせました。

"use client" は、必要な葉っぱ(末端のコンポーネント)にだけ付ける」というのが基本方針だと、身をもって学んだ出来事でした。

まとめ

この記事のポイント

  • "use client" はファイル先頭に書き、そのファイルをClient Componentの境界にする宣言
  • useState・イベントハンドラ・ブラウザAPIを使う場合にのみ必要になる
  • Client Componentからimportされたコンポーネントは、自動的にClientとして扱われる
  • Client Componentのchildrenとして渡したServer Componentは、Serverのまま維持される
  • "use client" は上流のファイルではなく、末端の小さいコンポーネントに付けるのが基本

次に読むべき記事

Server Component・Client Componentの使い分けが分かったところで、次はフォーム送信の新しい書き方を見ていきましょう。

次回は、Server Actionsの基本として、フォーム送信をサーバー側で処理する方法を解説します。

→ 次の記事:Server Actionsの基本:フォーム送信をサーバー側で処理する

タイトルとURLをコピーしました