Next.jsでReactコンポーネントを書いていて、おなじみのuseStateフックを使おうとしたら、突然こんなエラーに遭遇したことはありませんか?
Ecmascript file had an error
> 1 | import { useState } from "react";
| ^^^^^^^^
2 | import { useRouter } from "next/navigation";
3 |
You're importing a component that needs `useState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the `"use client"` directive.「useStateはクライアントコンポーネントでしか動かない」と言われても、Reactを始めたばかりの方や、Next.jsのApp Routerを使い始めたばかりの方にとっては「どういうこと?」と戸惑ってしまいますよね。
ご安心ください。このエラーはNext.jsの仕組みを理解すれば簡単に解決できます。この記事では、エラーの原因と具体的な解決策を分かりやすく解説します。
なぜエラーが起きるのか?サーバーコンポーネントの存在
このエラーの鍵を握っているのが、Next.js 13のApp Routerから導入された**サーバーコンポーネント (Server Components)**という概念です。
従来のReact開発(やNext.jsのPages Router)では、私たちが作るコンポーネントは基本的にすべて**クライアントコンポーネント (Client Components)**でした。これらはブラウザ(クライアント)に送られてから、JavaScriptによって描画され、ユーザーの操作に応じて状態を変化させます。useStateやuseEffect、onClickイベントなどは、まさにこのクライアント側での動作を前提とした機能です。
一方、Next.jsのApp Routerでは、デフォルトで全てのコンポーネントがサーバーコンポーネントとして扱われます。
サーバーコンポーネントの特徴:
- サーバー側でレンダリングが完了する。
- ページの初期表示が高速になる、SEOに有利などのメリットがある。
useStateやuseEffectなどのフックや、onClickのようなイベントハンドラは使用できない。
なぜなら、これらの機能はユーザーがブラウザで操作することが前提だからです。サーバー側では「ボタンがクリックされた」というイベントや、「状態を更新する」という対話的な処理は発生しません。
エラーメッセージは、「useStateのようなクライアント側の機能を使おうとしているけれど、このファイルはサーバーコンポーネントになっているよ」と教えてくれていたのです。
解決策はたった一行の追加
原因がわかれば解決は非常にシンプルです。エラーメッセージが親切に教えてくれている通り、ファイルの先頭に"use client";と記述するだけです。
これにより、Next.jsに対して「このコンポーネントはクライアントコンポーネントとして扱ってください」と宣言することができます。
修正前のコード (エラーが発生)
import { useState } from "react";
import { useRouter } from "next/navigation";
export default function Hoge() {
const [fuga, piyo] = useState("");
const router = useRouter();
// ...コンポーネントのロジック
return (
// JSX
);
}修正後のコード (解決!)
"use client"; // この一行を追加するだけ!
import { useState } from "react";
import { useRouter } from "next/navigation";
export default function Hoge() {
const [fuga, piyo] = useState("");
const router = useRouter();
// ...コンポーネントのロジック
return (
// JSX
);
}たったこれだけで、コンポーネントはクライアントコンポーネントとして扱われるようになり、useStateやその他のフック、イベントハンドラが問題なく使えるようになります。
まとめ
Next.jsのApp Routerで開発を行う際は、サーバーコンポーネントとクライアントコンポーネントの違いを意識することが重要です。
- サーバーコンポーネント (デフォルト): データの取得や静的な表示に使う。
useStateは使えない。 - クライアントコンポーネント (
"use client";を記述): ユーザーの操作に応じたインタラクティブなUIを構築する際に使う。useStateやuseEffectが使える。
もしuseStateやuseEffectを使っていて同様のエラーに遭遇したら、慌てずにファイルの先頭に"use client";を追加してみてください。
この知識が、あなたのNext.jsでの開発をよりスムーズに進める手助けになれば幸いです。