1
2

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ディレクトリで発生する NextRouter was not mounted エラーの解決方法

Last updated at Posted at 2024-07-07

はじめに

職務経歴書を登録できる簡単なアプリを開発していた際に、リダイレクト処理の実装中に NextRouter was not mounted エラーが発生しました。本記事では、このエラーの発生状況とその解決方法について説明します。

問題

以下のようなフォームを作成していました。

"use client";
import React, { useState } from "react";
import { Career, Project } from "../types/career";
import "./customStyles.css"; // カスタムCSSファイルをインポート
import { addDoc, collection } from "firebase/firestore";
import { db } from "@/firebase/config";
import { useRouter } from "next/router";

const CareerForm = () => {
  const router = useRouter();

  const [company, setCompany] = useState("");
  const [position, setPosition] = useState("");
  const [startDate, setStartDate] = useState("");
  const [endDate, setEndDate] = useState("");
  const [isCurrent, setIsCurrent] = useState(false);
  const [projects, setProjects] = useState<Project[]>(
    [
      { title: '', description: '' }
    ]
  )

  // 入力したデータをFirestoreに送信
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    const careerData: Career = {
      company,
      position,
      startDate,
      endDate: isCurrent ? "" : endDate,
      isCurrent,
      projects,
    };

    try {
      await addDoc(collection(db, "careers"), careerData);
      // フォームのリセットや成功メッセージの表示
      setCompany("");
      setPosition("");
      setStartDate("");
      setEndDate("");
      setIsCurrent(false);
      setProjects([{ title: "", description: "" }]);
      alert("経歴が保存されました");
      router.push("/careers");
    } catch (error) {
      console.error("Error adding document: ", error);
    }
  };


  return (
    <div className="container">
      <h1 className="heading">経歴の作成</h1>
      <div className="form-container">
        <form onSubmit={handleSubmit}>
          <div className="mb-4">
            <label className="block text-gray-700 text-sm font-bold mb-2">
              会社名
            </label>
            <input
              type="text"
              value={company}
              onChange={(e) => setCompany(e.target.value)}
              className="input"
            />
          </div>
          <div className="mb-4">
            <label className="block text-gray-700 text-sm font-bold mb-2">
              肩書・ポジション
            </label>
            <input
              type="text"
              value={position}
              onChange={(e) => setPosition(e.target.value)}
              className="input"
            />
          </div>
          <div className="mb-4">
            <label className="block text-gray-700 text-sm font-bold mb-2">
              在籍期間
            </label>
            <div className="flex space-x-4">
              <input
                type="month"
                value={startDate}
                onChange={(e) => setStartDate(e.target.value)}
                className="input"
              />
              <input
                type="month"
                value={endDate}
                onChange={(e) => setEndDate(e.target.value)}
                className="input"
              />
            </div>
            <div className="mt-2">
              <label className="inline-flex items-center">
                <input type="checkbox" className="form-checkbox" />
                <span className="ml-2 text-gray-700">現在在籍している</span>
              </label>
            </div>
          </div>
          <div className="mb-6">
            <label className="block text-gray-700 text-sm font-bold mb-4">
              主なプロジェクト・業務内容
            </label>
            {projects.map((project, index) => (
              <div key={index} className="border-t border-b py-6">
                <input
                  type="text"
                  name="title"
                  value={project.title}
                  onChange={(e) => handleProjectChange(index, e)}
                  className="input mb-8"
                  placeholder="見出しとなるタイトルを入力してください"
                />
                <textarea
                  name="description"
                  value={project.description}
                  onChange={(e) => handleProjectChange(index, e)}
                  className="input"
                  placeholder="業務内容を入力してください"
                  rows={4}
                ></textarea>
                <div className="flex justify-end">
                  <button
                    type="button"
                    onClick={() => handleRemoveProject(index)}
                    className="remove-button mt-4"
                  >
                    削除
                  </button>
                </div>
              </div>
            ))}
            <div className="my-8 flex justify-center">
              <button
                type="button"
                onClick={handleAddProject}
                className="button"
              >
                主なプロジェクト・業務内容を追加する
              </button>
            </div>
          </div>
          <div className="flex items-center justify-center">
            <button type="submit" className="submit-button mr-8">
              作成する
            </button>
            <button type="button" className="cancel-button">
              キャンセル
            </button>
          </div>
        </form>
      </div>
    </div>
  );
};

export default CareerForm;

Firestore にデータを送信後、特定のページにリダイレクトする機能を実装していました。具体的には、フォームの送信後に router.push("/careers") でリダイレクトを試みると、以下のエラーが発生しました。

スクリーンショット 2024-07-08 4.55.01.png

解決方法

解決方法として、next/routernext/navigation に置き換えることが有効でした。以下のようにインポート文を変更します。

- import { useRouter } from "next/router";
+ import { useRouter } from "next/navigation";

原因

原因は、appディレクトリ内でnext/routerのuseRouterフックを使っていたからです。

Next.jsのappディレクトリ(App Router)とpagesディレクトリ(Pages Router)では、useRouterフックの動作が異なります。appディレクトリ内では、 next/router ではなく next/navigation のuseRouterフックを使う必要があります。もし、app ディレクトリ内で next/router のuseRouterフックを使おうとすると、動作が異なるためにエラーが発生します。

参考

おわりに

本記事では、職務経歴書を登録するアプリ開発中に発生した NextRouter was not mounted エラーの原因と解決方法について説明しました。エラーの原因を理解し、適切な修正を加えることで、正常にリダイレクト処理を行うことができるようになります。同様のエラーに直面した際には、ぜひ参考にしてください。

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?