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
相关产品推荐
相关产品推荐

