2

I am trying to use router function to send user to login page but I get an error stating:

Unhandled Runtime Error Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

NextJs code:

"use client";
import React, { useEffect, useState } from "react";
import styles from "./page.module.css";
import useSWR from "swr";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import Image from "next/image";

const Dashboard = () => {

  const session = useSession();

  const router = useRouter();
  
  //NEW WAY TO FETCH DATA
  const fetcher = (...args) => fetch(...args).then((res) => res.json());

  const { data, mutate, error, isLoading } = useSWR(
    `/api/posts?username=${session?.data?.user.name}`,
    fetcher
  );

  if (session.status === "loading") {
    return <p>Loading...</p>;
  }

  if (session.status === "unauthenticated") {
    
      router?.push("/dashboard/login");
    
    
  }

  const handleSubmit = async (e) => {
    e.preventDefault();
    const title = e.target[0].value;
    const desc = e.target[1].value;
    const img = e.target[2].value;
    const content = e.target[3].value;

    try {
      await fetch("/api/posts", {
        method: "POST",
        body: JSON.stringify({
          title,
          desc,
          img,
          content,
          username: session.data.user.name,
        }),
      });
      mutate();
      e.target.reset()
    } catch (err) {
      console.log(err);
    }
  };

  const handleDelete = async (id) => {
    try {
      await fetch(`/api/posts/${id}`, {
        method: "DELETE",
      });
      mutate();
    } catch (err) {
      console.log(err);
    }
  };

  if (session.status === "authenticated") {
    return (
      <div className={styles.container}>
        <div className={styles.posts}>
          {isLoading
            ? "loading"
            : data?.map((post) => (
                <div className={styles.post} key={post._id}>
                  <div className={styles.imgContainer}>
                    <Image src={post.img} alt="" width={200} height={100} />
                  </div>
                  <h2 className={styles.postTitle}>{post.title}</h2>
                  <span
                    className={styles.delete}
                    onClick={() => handleDelete(post._id)}
                  >
                    X
                  </span>
                </div>
              ))}
        </div>
        <form className={styles.new} onSubmit={handleSubmit}>
          <h1>Add New Post</h1>
          <input type="text" placeholder="Title" className={styles.input} />
          <input type="text" placeholder="Desc" className={styles.input} />
          <input type="text" placeholder="Image" className={styles.input} />
          <textarea
            placeholder="Content"
            className={styles.textArea}
            cols="30"
            rows="10"
          ></textarea>
          <button className={styles.button}>Send</button>
        </form>
      </div>
    );
  }
};

export default Dashboard;

I am getting error at this line: router?.push("/dashboard/login");

I am also getting this warning in the console:

Warning: Cannot update a component (Router) while rendering a different component (Dashboard). To locate the bad setState() call inside Dashboard.

Shehbaz
  • 21
  • 2

1 Answers1

1

You are receiving this error because you calling a function directly in your component definition rather than wrapping it in a callback or an effect. You path validation should reside in a useEffect.

// here you validate the session status upon mount
useEffect(() => {
  if (session.status === "unauthenticated") {
    router?.push("/dashboard/login");
  }
}, [session.status]);

// this is ok since you're just conditionally rendering something
if (session.status === "loading") {
  return <p>Loading...</p>;
}

If you can access the session object on the server side it may be a feasible approach to contain this logic in a dedicates server component.

Fabio Nettis
  • 1,150
  • 6
  • 18
  • After using useEffect() Hook, I am getting following error: ` Warning: React has detected a change in the order of Hooks called by Dashboard. This will lead to bugs and errors if not fixed. Warning: Cannot update a component (`HotReload`) while rendering a different component (`Dashboard`). To locate the bad setState() call inside `Dashboard`` – Shehbaz Jun 23 '23 at 15:36
  • Swap the order of the code so there are no early returns before any React hook calls. All React hooks must be unconditionally called each render cycle. You should add the [React hooks-rules eslint plugin](https://legacy.reactjs.org/docs/hooks-rules.html#eslint-plugin) to your project to catch issues like this. – Drew Reese Jun 24 '23 at 07:04
  • My bad, yeah that would break the rules of hooks, I have edited my answer accordingly. – Fabio Nettis Jun 24 '23 at 17:07