You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS调用router.push跳转时触发Maximum update depth exceeded错误

解决NextJS Dashboard组件中router.push导致的无限循环错误

问题现象

在NextJS的Dashboard组件中,尝试通过router.push("/dashboard/login")将未认证用户跳转至登录页面时,出现以下问题:

  • 未处理运行时错误:

    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.

  • 控制台警告:

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

错误触发位置为代码中的router?.push("/dashboard/login");行。

问题原因

直接在组件渲染阶段调用router.push会触发路由状态更新,路由更新又会导致Dashboard组件重新渲染,重新渲染时再次执行router.push,形成无限循环。同时React禁止在组件渲染过程中更新其他组件(如Router),因此抛出警告。

解决方案

将跳转逻辑移至useEffect钩子中,useEffect会在组件渲染完成后执行,不会干扰渲染流程,也不会触发无限循环。

修改后的关键代码

const Dashboard = () => {
  const session = useSession();
  const router = useRouter();

  // ...其他代码

  useEffect(() => {
    if (session.status === "unauthenticated") {
      router?.push("/dashboard/login");
    }
  }, [session.status, router]);

  // ...其他代码
};

完整修改后的组件代码

"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();
  
  // 数据获取函数
  const fetcher = (...args) => fetch(...args).then((res) => res.json());

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

  useEffect(() => {
    // 在渲染完成后处理跳转
    if (session.status === "unauthenticated") {
      router?.push("/dashboard/login");
    }
  }, [session.status, router]);

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

  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>
    );
  }

  // 避免组件无返回值的问题
  return null;
};

export default Dashboard;

额外说明

  • 添加useEffect的依赖数组[session.status, router],确保只有当会话状态变化或router实例更新时才执行跳转逻辑。
  • 在组件末尾添加return null;,避免当session.status为unauthenticated时组件没有返回值的问题。

内容的提问来源于stack exchange,提问作者Shehbaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:25:00