NextJS中useRouter的router.push()无响应问题求助
你遇到的问题核心是登录成功后直接调用router.push('/')未触发预期跳转,但通过useEffect监听userId变化后调用却生效,这本质是Next.js客户端导航与状态同步的时机问题,以下是具体原因和解决办法:
核心原因
登录状态未及时同步
调用signIn.attemptFirstFactor成功后,userId等登录状态可能还未完成更新(比如状态管理库、全局上下文的状态同步存在延迟)。此时直接执行router.push('/'),首页的权限校验组件可能读取到的还是旧的未登录状态,会自动重定向回登录页,看起来像是push没生效,但实际是跳转后又被拦截回原页面。客户端导航的特性限制
router.push是Next.js的客户端导航,不会刷新页面。如果首页组件依赖的登录状态没有触发重新渲染,页面会保持旧状态,导致你误以为跳转未执行。而router.reload()会强制刷新页面,此时所有状态会重新初始化,自然能读取到最新的登录状态。
解决方案
方案1:等待登录状态同步后再跳转
不要在authHandler中直接调用router.push,而是通过useEffect监听登录状态的变化(比如userId或专门的登录状态标识),确保状态更新完成后再触发跳转:
// 保留你的authHandler逻辑,移除里面的router.push const authHandler = useCallback(async (emailCode) => { setIsLoading(true); try { await signIn.attemptFirstFactor({ strategy: 'email_code', code: emailCode, }); createAlerts('Success', false); } catch (error) { handleForeignAlert(error, 'Code is incorrect or expired'); } finally { setIsLoading(false); } }, [signIn, createAlerts, handleForeignAlert]); // 监听userId变化触发跳转 useEffect(() => { if (userId) { router.push('/'); } }, [userId, router]);
方案2:强制跳转时刷新页面(临时应急方案)
如果需要在authHandler中直接跳转,可以给router.push添加forceRefresh参数,强制刷新页面以确保状态同步:
router.push('/', undefined, { forceRefresh: true });
注意:这种方式会放弃客户端导航的优势,不推荐作为长期方案,仅用于临时调试或特殊场景。
方案3:检查首页的权限拦截逻辑
排查首页组件中是否存在权限校验代码(比如路由守卫、高阶组件),确保校验逻辑能实时响应登录状态的变化。比如如果使用了useSWR或react-query获取用户信息,需要确保数据已完成更新再进行权限判断。
内容的提问来源于stack exchange,提问作者rolias4031

