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

Next.js使用高阶组件(HOC)做路由保护时出现登录组件闪屏问题

问题根因

闪屏是逻辑时序问题导致的,和Strict Mode、开发环境无关:

  • 你将accessGranted的初始值设为false
  • useEffect回调仅会在组件首次渲染完成后才执行,因此首次渲染必然返回Login组件,等到读取localStorage完成、更新状态后才会切换到Dashboard,这个时间差就是你看到的闪屏现象。

修复方案

方案1:同步初始化状态(适合纯静态导出/客户端渲染场景)

直接在useState初始化时同步读取localStorage,不需要等待useEffect执行,首次渲染就能拿到正确的权限状态:

const protectedRoutes = (WrappedComponent: any) => {
 return (props: any) => {
    const Router = useRouter();
    // 初始化时同步读取登录状态,加window判断避免SSR/SSG构建报错
    const [accessGranted, setAccessGranted] = useState(() => {
      return typeof window !== 'undefined' && !!localStorage.getItem("user")
    });

    useEffect(() => {
        if (!accessGranted) {
            Router.replace('/');
        }
    }, [accessGranted, Router]);

    if (accessGranted) {
        return <Dashboard content={<WrappedComponent {...props} />}/> 
    } else {
        return <Login/>
    }
  };
 };

方案2:增加加载状态(兼容SSR/SSG场景,避免hydration不匹配)

如果你的项目用了服务端渲染/静态生成,客户端和服务端初始渲染内容不一致会触发hydration警告,此时加一个加载态即可解决:

const protectedRoutes = (WrappedComponent: any) => {
 return (props: any) => {
    const Router = useRouter();
    const [isLoading, setIsLoading] = useState(true);
    const [accessGranted, setAccessGranted] = useState(false);

    useEffect(() => {
        const hasUser = !!localStorage.getItem("user");
        setAccessGranted(hasUser);
        if (!hasUser) {
            Router.replace('/');
        }
        setIsLoading(false);
    }, [Router]);

    // 加载阶段渲染统一的加载占位,避免闪屏和hydration错误
    if (isLoading) {
        return <div className="global-loading">加载中...</div>
    }

    if (accessGranted) {
        return <Dashboard content={<WrappedComponent {...props} />}/> 
    } else {
        return <Login/>
    }
  };
 };

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:18:04