React组件集成触发Maximum call stack size exceeded错误求助
排查 TrapFocus.js 栈溢出错误原因
核心可能原因
- 焦点陷阱循环触发:Dialog关闭或应用切换后,TrapFocus组件恢复焦点时,错误将焦点指向自身管理的元素,或与DropdownMenu的焦点逻辑冲突,导致焦点在两个组件的焦点陷阱间反复跳转,触发无限递归。
- 未清理焦点监听:Dialog打开时TrapFocus添加的全局焦点监听(如
focusin/focusout),在Dialog关闭后未正确移除,切换应用返回时残留监听与新逻辑冲突,引发循环。 - DOM层级冲突:若ResearchDialog挂载在DropdownMenu的DOM层级内,关闭Dialog时DropdownMenu的DOM变化(如菜单收起)会销毁TrapFocus的目标元素,但组件仍引用该元素,触发错误的焦点查询循环。
排查与修复步骤
- 调整Dialog挂载位置:将ResearchDialog通过Portal挂载到
body根节点,避免DropdownMenu的DOM变更影响Dialog的焦点清理逻辑。 - 手动指定焦点恢复目标:在Dialog的
onClose回调中,强制将焦点设置为DropdownMenu的触发按钮,覆盖TrapFocus的默认行为,示例代码:const handleDialogClose = () => { setDialogOpen(false); dropdownTriggerRef.current?.focus(); }; - 检查监听清理逻辑:查看TrapFocus组件的生命周期(如React的
useEffect清理函数),确保Dialog卸载时移除所有全局焦点监听;若使用第三方UI库,尝试升级到最新稳定版,排查是否存在已知焦点管理bug。 - 追踪焦点流转:在浏览器控制台添加焦点事件监听,打印每次焦点变化的元素,定位循环触发的焦点路径:
document.addEventListener('focus', (e) => console.log('Focused element:', e.target), true);
内容的提问来源于stack exchange,提问作者Tan Jin Peng
相关产品推荐
相关产品推荐

