0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Next.js】 App Routerの先頭行、結局どれを使えばいいの? 5種類の使い分けまとめ

0
Last updated at Posted at 2026-02-26

🎯 この記事の対象者

  • Next.jsは先頭に色々書けるのは知ってる
  • "use client" がクライアント側なのは覚えてる
  • でも他の書き方って似てるし、どう違うのかうろ覚えだし実はよく分かってない🤔

そんな僕のために書いた記事です。

Next.js (App Router) 「動作場所」5種類まとめ

  • Next.jsのApp Routerは先頭の宣言(ディレクティブやインポート)が複数ある
  • この宣言で コードの動作場所が、サーバー側かクライアント側かが決まる
  • 主要な5種類とそれぞれの役割について整理

💻 1."use client" (Client Components)

  • 目的と概要:
    • ブラウザ側のユーザー操作(ボタンクリックなど)を記述したい
    • useStateuseEffect などのReactフックを使いたい
  • 特徴・挙動:
    • 初期ページロード時には、実はサーバー側で事前レンダリング(SSR)される
    • その後、「RSCペイロード」とコンポーネントのJSとしてクライアントへ送信
    • ブラウザ側でJavaScriptがアタッチ(ハイドレーション)されて、初めてクリックなどが可能になる

RSCペイロード(React Server Components Payload)
Reactがクライアント側で画面のツリー構造を構築・更新するための、設計図のような特殊なデータ形式。

🏠 2.なにもなし (Server Components)

  • 目的と概要:
    • Next.js(App Router)の基本(デフォルト状態)
    • ブラウザからのGETやPOSTの結果をサーバー側で作成する
    • 検索エンジン(SEO)に完成したページを読み込ませたい
    • データベースや外部APIから、安全かつ直接データを取得して画面を作りたい
    • 初期状態の画面表示をとにかく高速化したい
  • 特徴・挙動:
    • サーバー側で処理が完結し、結果(HTMLとRSCペイロード)だけがブラウザに送られる
    • ブラウザ側で動くJSコードが一切含まれないため、ページ全体のファイルサイズが劇的に軽くなる
    • クライアントバウンダリに注意
  • ここが勘違いポイント:
    • 「なにも書かない=古いReact(Pages Router)」ではない
    • 「なにも書かない=最新のサーバー専用モード」

クライアントバウンダリ
"use client"のファイルからインポートして使われた場合は、自動的にクライアント側で動くコンポーネントに変化する

⚡ 3."use server" (Server Actions)

  • 目的と概要:
    • ブラウザから「入力結果(フォーム)送信」など、サーバー側の処理を直接呼び出したい
      • submitボタンを押したときの動作
    • ブラウザからページ内の一部だけをサーバーから取得して書き換えたい
      • RPC(リモートプロシジャーコール)として、fetchも可能(fetchされる側)
  • 技術的な裏側:
    • クライアントコンポーネントから通常の関数呼び出しでサーバーアクションを呼び出せる
    • 各関数に対して自動的にエンドポイントが作成される (Next.jsの強み)
    • 実際には裏側でそのエンドポイントに対してクライアントからPOSTリクエストが飛んでいる
  • 特徴・挙動:
    • コンポーネント(画面)ではなく「関数」の先頭(またはファイル全体)につける宣言
    • ブラウザ側からは関数の『中身』は見えない(安全に秘匿情報を扱える)
  • ここが勘違いポイント:
    • 「Server Components(サーバー側で表示するやつ)」を書きたい時に "use server" と書くのは間違い
    • "use server" はあくまで「サーバー側の関数(アクション)」を呼び出すためのもの

■ 得意先のメンテナンス画面のクライアントコンポーネント

const onSubmit = async (data: 得意先Input) => {
  const payload = isEdit ? { ...data, 得意先ID: target?.得意先ID } : data;
  const res = await save得意先(payload as 得意先Output, isEdit);
  if (res.success) {
    toast.success(isEdit ? "更新しました" : "登録しました");
    onClose();
  } else {
    toast.error(res.error || "保存に失敗しました");
  }
};

ここでサーバーアクションを呼んでます
サーバーへPOSTされて結果を取得する時間を考えたら
当然非同期処理なので await で呼び出す 必然性がよく分かります

const res = await save得意先(payload as 得意先Output, isEdit);

■ 呼び出されるサーバーアクション

"use server";
export async function save得意先(data: 得意先Input, isEdit: boolean) {
  try {
    const validated = 得意先Model.parse(data);
(以下省略)

4.import "server-only";

  • 目的と概要:
    • 絶対にサーバー側でのみ動作させたい
    • データベースのパスワードや、サーバー側でしか動かない処理が、誤ってブラウザ側に漏れるのを絶対に防ぎたい
    • DBアクセスなど特に秘匿性の高い処理に記述
  • 特徴・挙動:
    • サーバー側でのみ動作することを強制する「安全装置」
    • サーバーアクションやサーバーコンポーネントからのみ呼び出し可能
    • クライアント側から呼び出そうとするとビルド時にエラー

5.import "client-only";

  • 目的と概要:
    • 絶対にブラウザ側でのみ動作させたい
    • windowlocalStorage など、ブラウザ(クライアント)にしか存在しない機能を使う処理が、誤ってサーバー側で実行されてクラッシュするのを防ぎたい
  • 特徴・挙動:
    • クライアント側でのみ動作することを強制する「安全装置」
    • クライアントコンポーネントからのみ呼び出し可能
    • サーバー側で呼び出そうとするとビルド時にエラー

✅ まとめ

基本は何も書かない。(Server Components)
ブラウザの動きが必要になったら "use client" を足す。
✨これが現代のNext.jsの王道スタイル

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?