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

Next.js路由渲染取消错误:基础鉴权与路由保护问题排查

Next.js "Cancel rendering route" 错误排查与修复

问题根源

  1. 状态不共享:useUserSession被重复调用(_app.tsx、MainLayout、LoginLayout各初始化一次),每个调用都会创建独立的状态实例。点击登录后修改的是LoginLayout内的局部状态,而Home页面读取的是_app.tsx中的初始未登录状态,触发循环跳转,最终导致路由渲染被取消。
  2. 重复包裹Context Provider:每个布局组件都重新套了userSession.Provider,覆盖了全局状态,进一步加剧状态不一致问题。
  3. 路由跳转逻辑缺陷:Home页面的useEffect跳转基于不一致的状态判断,引发循环跳转触发Next.js的路由渲染取消机制。

修复方案

1. 统一全局状态管理

仅在_app.tsx中初始化useUserSession,通过Context将状态全局传递,所有子组件通过useContext获取状态,不再单独调用useUserSession。

2. 移除布局中的重复Provider

删除MainLayout和LoginLayout内的userSession.Provider,仅保留_app.tsx中的全局Provider。

3. 修正路由保护逻辑

确保跳转判断基于全局统一状态,避免循环跳转。


修改后的关键代码

_app.tsx(全局状态入口)

import { AppPropsWithLayout } from 'next/app';
import useUserSession from '../hooks/useUserSession';
import userSession from '../contexts/userSession';

export default function App({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page);
  const { username, userLoggedIn, login, loggout } = useUserSession();

  return getLayout(
    <userSession.Provider value={{ isLoggedIn: userLoggedIn, username, login, loggout }}>
      <Component {...pageProps} />
    </userSession.Provider>
  );
}

MainLayout.tsx(移除重复Provider)

import { ReactNode } from 'react';

function MainLayout({ children }: { children: ReactNode }) {
  return (
    <>
      <PageHeader />
      <UserSideBar />
      <div className="pageContent">
        {children}
      </div>
    </>
  );
}

export default MainLayout;

LoginLayout.tsx(移除重复Provider)

import { ReactNode } from 'react';

function LoginRegisterLayout({ children }: { children: ReactNode }) {
  return (
    <>
      <PageHeader />
      {children}
    </>
  );
}

export default LoginRegisterLayout;

Home.tsx(修正路由保护)

import { useEffect, useContext } from 'react';
import { useRouter } from 'next/router';
import userSession from '../contexts/userSession';

const Home: PageWithLayout = () => {
  const userSessionData = useContext(userSession);
  const router = useRouter();

  useEffect(() => {
    if (!userSessionData.isLoggedIn) {
      // 使用replace避免历史记录堆积
      router.replace('/login');
    }
  }, [userSessionData.isLoggedIn, router]);

  // 原页面内容不变...
};

Home.getLayout = function getLayout(page: ReactElement) {
  return <MainLayout>{page}</MainLayout>;
};

export default Home;

可选:优化useUserSession初始状态

import { useRouter } from "next/router";
import { useCallback, useState } from "react";

const useUserSession = () => {
  // 明确初始类型,避免undefined导致判断错误
  const [username, setUsername] = useState<string>('');
  const [userLoggedIn, setUserLoggedIn] = useState<boolean>(false);
  const router = useRouter();

  const login = useCallback(() => {
    setUsername('Admin');
    setUserLoggedIn(true);
    router.push("/");
  }, [router]);

  const loggout = useCallback(() => {
    setUsername('');
    setUserLoggedIn(false);
    router.push("/login");
  }, [router]);

  return { username, userLoggedIn, login, loggout };
};

export default useUserSession;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:15:29