KAKUTA TECH BLOG

Blog Article

サーバーコンポーネントとクライアントコンポーネントについて

はじめに

Next.js を学び始めると、必ずと言っていいほど登場するのが「サーバーコンポーネント」と「クライアントコンポーネント」です。名前は難しそうですが、役割を正しく理解すると「なぜ分かれているのか」「どう使い分けるべきか」が自然と見えてきます。

まずは 2 つのコンポーネントの概要を説明し、その後にそれぞれの特徴や実装方法、使い分け、そしてサーバーからクライアントへ props を渡す流れまでを解説します。

参考にしたリンク

サーバーコンポーネントとは何か

サーバーコンポーネントとは、その名の通り「サーバー上で実行されるコンポーネント」です。ブラウザではなく、Next.js が動いているサーバー側で処理され、HTML の形になってからブラウザに送られます。一言で言うなら、「画面を作る前の重たい仕事を担当する存在」です。

データベースからデータを取得したり、API にアクセスしたり、外部サービスと通信したりといった処理を、安全かつ効率よく行うために使われます。

サーバーコンポーネントでできること

サーバーコンポーネントでできることを一言でまとめると、「安全に、効率よくデータを扱うこと」です。

サーバー上で動くため、次のような処理が可能です。

  • データベースへの直接アクセス
  • 環境変数や秘密鍵の使用
  • 重たい計算処理
  • API からのデータ取得

これらはブラウザで行うと、セキュリティやパフォーマンスの問題が出やすい処理です。そのため、サーバーコンポーネントに任せることで、安心してアプリを作ることができます。

いつサーバーコンポーネントを使うのか

サーバーコンポーネントは、「画面を表示する前に必要な情報を集めたいとき」に使います。

たとえば、ブログ記事一覧ページを考えてみてください。記事のタイトルや本文は、データベースや外部 API から取得する必要があります。このような処理は、ユーザーが何か操作する前に完了している方が自然です。そのため、「最初に表示する画面を作るための処理」は、サーバーコンポーネントに向いています。

なぜサーバーコンポーネントが必要なのか

もしすべてをクライアントコンポーネントで作った場合、次のような問題が起きます。

  • ブラウザに不要な JavaScript が大量に送られる
  • 秘密情報を安全に扱えない
  • 初期表示が遅くなる

サーバーコンポーネントがあることで、「ブラウザに送らなくていい処理」をサーバー側で完結させることができます。

これにより、表示速度が向上し、セキュリティも保たれます。

サーバーコンポーネントの実装方法

Next.js の App Router では、特別な指定をしない限り、コンポーネントは自動的にサーバーコンポーネントになります。

// app/posts/page.tsx
export default async function PostsPage() {
  const posts = await fetch("<https://example.com/posts>").then(res => res.json());

  return (
    <div>
      <h2>記事一覧</h2>
      {posts.map((post: any) => (
        <p key={post.id}>{post.title}</p>
      ))}
    </div>
  );
}

このコードでは、fetch を使ってデータを取得していますが、これはサーバー上で実行されます。

その結果だけが HTML としてブラウザに送られます。

クライアントコンポーネントとは何か

クライアントコンポーネントは、ブラウザ上で動作するコンポーネントです。ユーザーがクリックしたり、入力したりした操作に反応して画面を変える役割を持ちます。

一言で言うなら、「ユーザーと直接やり取りする存在」です。

React の useStateuseEffect といったフックを使えるのが特徴で、インタラクティブな UI を作るために欠かせません。

クライアントコンポーネントでできること

クライアントコンポーネントを一言で表すなら、「ユーザー操作に反応できるコンポーネント」です。

次のようなことができます。

  • ボタンをクリックして画面を切り替える
  • フォーム入力をリアルタイムで反映する
  • モーダルやアコーディオンの開閉

これらは、ユーザーの操作に応じて状態が変わるため、ブラウザ上での処理が必要です。

いつクライアントコンポーネントを使うのか

クライアントコンポーネントは、「ユーザーの操作によって画面が変わるとき」に使います。たとえば、いいねボタンや、入力フォーム、タブ切り替えなどが該当します。

これらはサーバーで完結できず、ユーザーの操作を即座に反映する必要があります。

なぜクライアントコンポーネントが必要なのか

もしすべてをサーバーコンポーネントで作ろうとすると、次の問題が起きます。

  • クリックするたびにサーバー通信が必要になる
  • 操作のたびに画面が再描画され、体験が悪くなる

クライアントコンポーネントがあることで、ブラウザ内で素早く状態を更新でき、快適な操作感を実現できます。

クライアントコンポーネントの実装方法

クライアントコンポーネントを作るには、ファイルの先頭に "use client" を記述します。

"use client";

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      クリック数: {count}
    </button>
  );
}

この宣言があることで、「このコンポーネントはブラウザで動く」ということを Next.js に伝えています。

サーバーコンポーネントからクライアントコンポーネントへ props を渡す流れ

処理は重いものほどサーバーで行い、操作はクライアントに任せる、という考え方が基本です。サーバーコンポーネントで取得・加工したデータを、props としてクライアントコンポーネントに渡します。クライアント側は、そのデータを使って画面操作を行います。

実際の流れ

// サーバーコンポーネント
import ClientPost from "./ClientPost";

export default async function Page() {
  const post = await fetch("<https://example.com/post/1>").then(res => res.json());

  return <ClientPost post={post} />;
}
"use client";

export default function ClientPost({ post }: { post: any }) {
  return <h3>{post.title}</h3>;
}

このように、サーバーで取得したデータをそのまま props として渡します。

クライアントは「受け取ったデータを使って表示や操作をするだけ」です。

サーバーからクライアントへ渡せるもの、渡せないもの

サーバーからクライアントへ渡せるのは、「JSON に変換できるデータ」のみです。

渡せるもの

  • 文字列
  • 数値
  • 配列
  • オブジェクト(中身が JSON 形式のもの)

渡せないもの

  • 関数
  • クラスのインスタンス
  • Date オブジェクト(そのままでは不可)

渡せないものを無理に渡そうとすると、エラーが発生します。

これは、サーバーとクライアントが別の実行環境で動いているためです。

具体例

処理内容

適したコンポーネント

記事データ取得

サーバーコンポーネント

記事一覧表示

サーバーコンポーネント

いいねボタン

クライアントコンポーネント

フォーム入力

クライアントコンポーネント

まとめ

  • サーバーコンポーネントは、重たい処理やデータ取得を担当します。
  • クライアントコンポーネントは、ユーザー操作に反応する UI を担当します。
  • 処理はサーバー、操作はクライアントという役割分担が重要です。
  • サーバーからクライアントへ渡せるのは JSON に変換できるデータのみです。

この考え方を意識することで、Next.js の設計が一気に理解しやすくなります。

ブログや Web アプリを作る際は、「これはどちらの仕事か?」と考えながら実装してみてください。