Next.js使用shallow routing导致页面导航按钮/链接失效
问题根本原因
核心bug是你的shallow路由更新逻辑写在了无依赖数组的useEffect中:
useEffect(() => { router.push(`/card/${card?.id}`, undefined, { shallow: true }) });
React中不传第二个依赖参数的useEffect,会在组件每一次渲染完成后全量执行,这就直接触发了无限循环:
- 页面首次加载 → 执行shallow push更新URL
- 路由状态变化触发组件重渲染 → 再次执行shallow push
- 循环往复,Next.js的路由事件队列被持续的同页面shallow更新占满
- 点击首页按钮触发的跨页导航请求,会被不断插队的同页面路由更新反复打断、覆盖,完全无法执行,哪怕换成
Link组件、手写onClick自定义导航逻辑也没用——路由实例始终处于“处理当前页shallow更新”的状态,根本不会响应跨页跳转。
你用原生window.history.pushState能临时绕过问题,本质是因为这个原生API不会触发Next.js路由状态更新、不会触发组件重渲染,自然不会形成死循环,但这种写法完全绕过了Next的路由系统,确实存在状态不同步的潜在风险。
修复方案
给useEffect加上正确的依赖数组,同时增加判断逻辑,保证URL更新仅在card.id实际变化、且当前URL和目标ID不一致时才执行,从根源切断无限循环:
useEffect(() => { // 避免card为空、或URL已经匹配当前卡片ID时重复触发路由更新 if (card?.id && router.query.id !== String(card.id)) { router.push(`/card/${card.id}`, undefined, { shallow: true }) } // 仅在卡片ID、路由实例、路由参数变化时才执行effect }, [card?.id, router, router.query.id]);
修改后无限路由更新的死循环会直接消失,首页按钮、其他所有页面导航功能都会恢复正常。
额外可优化的点
- 不要直接修改props传入的
card对象:原代码中if (card !== null) { card.dateUsed = used.toDate() }属于React反模式,props是只读的,直接修改不会触发稳定的组件重渲染,还会导致状态不可预测。建议用useState初始化card数据,接口请求成功后通过setState方法更新视图。 - Prisma的Date类型序列化不需要用
JSON.parse(JSON.stringify(card))这种hack写法,可以在返回props时手动把Date转成ISO字符串,或者用常规序列化工具处理即可,性能更好也更易维护。
内容的提问来源于stack exchange,提问作者Graham Charles
相关产品推荐
相关产品推荐

