👀

"Next.jsを書いていて本気でつまずいたポイントまとめ(初心者〜中級向け)"

に公開

Next.jsを書いていて本気でつまずいたポイント(コード付きでシンプル解説)

こんにちは、シュートです。普段は学生をしながらTypeScriptを用いて、個人開発やチーム開発をしています!
Next.js と React を使う中で、「文法は知ってるのに挙動がよく分からない」場面が何度もありました。

この記事では、自分が本当に詰まった箇所だけを、原因 → コード例 → 解決策 の流れでシンプルにまとめます。


1. useState の値が更新されない問題

まず誰もが通る道。

const [count, setCount] = useState(0);

const handleClick = () => {
  console.log(count); // 0 のまま
  setCount(count + 1);
  console.log(count); // 0 のまま
};

React の state 更新は同期ではなく “次のレンダーで反映される” のがポイント。

✔️ 解決策:関数型アップデート

setCount(prev => prev + 1);

2. useEffect の依存配列で無限ループ

useEffect(() => {
  fetchData();
}, [data]); // data を fetchData が更新 → 無限ループ

✔️ 原因

依存配列に「更新される値」を入れている。

✔️ 解決策

useEffect(() => {
  fetchData();
}, []); // 初回だけ

3. props が更新されない / 反映されない

// 親
<Child value={count} />

// 子
useEffect(() => {
  console.log(value); // 更新されないように見える
}, []); 

✔️ 解決策

useEffect(() => {
  console.log(value);
}, [value]);

4. Next.js の “Server / Client” ミス

// Server Component 内
localStorage.getItem("token"); // ❌ ReferenceError

✔️ 対策

"use client";

useEffect(() => {
  const token = localStorage.getItem("token");
}, []);

5. fetch が“2回実行される”問題

useEffect(() => {
  fetch("/api/data");
}, []);

✔️ 原因

StrictMode による二回実行。

✔️ 対策(1回だけにしたい場合)

const data = await fetch("https://example.com").then(res => res.json());

6. app router のルーティング混乱

// app/users/[id]/page.tsx
export default function UserPage({ params }: { params: { id: string } }) {
  return <div>User: {params.id}</div>;
}

覚えるポイントは2つだけ:

  • フォルダ名 = URL
  • [] = 動的パラメータ

7. Next.js で意識すると楽になること

  • state の“持ち主”は一箇所にまとめる
  • state は “その場では更新されない”
  • useEffect の依存配列が挙動のすべて
  • Server / Client の境界を意識する
  • フォルダ = ルーティング

おわりに

今後は以下の記事を執筆予定

  • Gemini / GPT-5 / Claude に同じタスクを投げた比較記事
  • 各AI API(Responses / Gemini / Claude API)の実装メモ
  • Zod / Firestore / Stripe まわりのトラブル集
  • “AIと一緒に開発するときの流れ” の話

学生エンジニアとしての実体験ベースで書いていくので、ゆるく読んでもらえたら。

Discussion