Dev Study
← 解説「Client Components — "use client" でブラウザ上で動かす」に戻る

サンプルコードで身につける: Client Components — "use client" でブラウザ上で動かす

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1最小のカウンター

"use client" を付けて useState とクリックに反応する、Client Component の最小形です。この1行がないと useState の行でエラーになる、という境界線を確かめる基本の例です。

// app/counter.tsx
"use client"; // この1行で Client Component になる

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      {count} 回クリックされました
    </button>
  );
}
// "use client" を消すと useState の行でエラーになる。

2開閉するメニュー

true / false の状態で表示を切り替える、インタラクティブ UI の基本パターンです。ハンバーガーメニューやアコーディオンなど「クリックで開閉するもの」はすべてこの形の応用で、必ず Client Component になります。

"use client";

import { useState } from "react";

export default function MobileMenu() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <div>
      <button onClick={() => setIsOpen(!isOpen)}>
        {isOpen ? "閉じる" : "メニュー"}
      </button>
      {isOpen && (
        <ul>
          <li>ホーム</li>
          <li>商品一覧</li>
          <li>お問い合わせ</li>
        </ul>
      )}
    </div>
  );
}

3入力に反応するテキストフォーム

入力のたびに onChange で状態を更新し、画面に即座に反映する例です。文字数カウンターやプレビュー表示など「タイプした瞬間に何かが変わる UI」は、ブラウザ上で動く Client Component でしか作れません。

"use client";

import { useState } from "react";

export default function CommentBox() {
  const [text, setText] = useState("");
  const limit = 100;
  return (
    <div>
      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="コメントを入力"
      />
      <p>
        あと {limit - text.length} 文字 {/* 入力のたびに即更新 */}
      </p>
    </div>
  );
}

4タブ切り替えUI

「いま選ばれているタブ」を文字列の状態で持ち、クリックで表示を切り替える例です。設定画面やダッシュボードで頻出のパターンで、boolean では足りない「複数の選択肢から1つ」の状態管理を学べます。

"use client";

import { useState } from "react";

const tabs = [
  { key: "spec", label: "仕様", content: "サイズ: 30cm / 重さ: 1.2kg" },
  { key: "review", label: "レビュー", content: "星4.5(120件)" },
  { key: "qa", label: "Q&A", content: "質問: 3件" },
];

export default function ProductTabs() {
  const [active, setActive] = useState("spec");
  const current = tabs.find((t) => t.key === active);
  return (
    <div>
      {tabs.map((tab) => (
        <button key={tab.key} onClick={() => setActive(tab.key)}>
          {tab.label}
        </button>
      ))}
      <p>{current?.content}</p>
    </div>
  );
}

5商品リストの絞り込み検索

検索ボックスの入力に合わせて一覧をその場で絞り込む、実務でよく作る画面です。入力という操作に1文字ごとに反応する必要があるため Client Component の出番で、「操作に反応するなら Client」という使い分け基準の典型例です。

"use client";

import { useState } from "react";

const products = ["りんご", "りんごジュース", "みかん", "ぶどう", "もも"];

export default function ProductSearch() {
  const [keyword, setKeyword] = useState("");
  const filtered = products.filter((p) => p.includes(keyword));
  return (
    <div>
      <input
        value={keyword}
        onChange={(e) => setKeyword(e.target.value)}
        placeholder="商品名で検索"
      />
      <ul>
        {filtered.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
}