React路由切换后侧边栏函数触发TypeError报错求助
解决方案
问题根源
当路由切换到/signin时,Leftsidebar组件已被卸载,但之前通过$(window).on绑定的滚动、resize事件并未移除。触发这些事件时,updateSidebarPosition函数会尝试获取不存在的footer元素(AuthLayout中无Footer组件),调用offset().top时就会抛出Cannot read properties of undefined (reading 'top')错误。你之前仅判断了侧边栏元素的存在,未处理Footer不存在的情况,因此无效。
修复步骤
- 组件卸载时移除事件监听:在
Leftsidebar组件中添加componentWillUnmount钩子,移除绑定在window上的事件,避免组件卸载后事件仍被触发。 - 同时判断侧边栏和Footer元素是否存在:在
updateSidebarPosition函数开头,检查侧边栏和Footer元素是否存在,只要有一个不存在就直接终止函数执行。 - 修正事件绑定的命名空间:你之前绑定resize事件时用了
scroll.resize命名空间,应改为resize.updateSidebar,确保后续能精准移除事件。
修正后的代码
componentDidMount() { const $ = window.$; const leftsidebar = $("#left-sidebar"); function updateSidebarPosition() { // 先判断侧边栏和Footer是否存在,不存在直接返回 if (!leftsidebar.length || !$("footer").length) { return; } var footerTop = $("footer").offset().top; var sidebarHeight = leftsidebar.outerHeight(); var stopPoint = footerTop - sidebarHeight - 54; if ($(window).scrollTop() >= stopPoint) { leftsidebar.css({ position: "absolute", top: stopPoint + 54 + "px", }); } else { leftsidebar.css({ position: "fixed", top: "56px", }); } } // 初始化调用 updateSidebarPosition(); var isScrolling = false; // 保存事件处理器引用,方便后续移除 const scrollHandler = function () { if (!isScrolling) { isScrolling = true; window.requestAnimationFrame(function () { updateSidebarPosition(); isScrolling = false; }); } }; const resizeHandler = function () { updateSidebarPosition(); }; // 绑定事件并添加命名空间 $(window).on("scroll.updateSidebar", scrollHandler); $(window).on("resize.updateSidebar", resizeHandler); // 将处理器挂载到组件实例上,供卸载时使用 this.scrollHandler = scrollHandler; this.resizeHandler = resizeHandler; } // 组件卸载时移除事件监听 componentWillUnmount() { const $ = window.$; $(window).off("scroll.updateSidebar", this.scrollHandler); $(window).off("resize.updateSidebar", this.resizeHandler); }
额外优化建议
尽量避免在React中使用jQuery操作DOM,推荐使用React的createRef(类组件)或useRef(函数组件)获取DOM元素,用原生JS实现位置计算,更符合React设计理念:
// 类组件示例 constructor(props) { super(props); this.sidebarRef = React.createRef(); } componentDidMount() { const sidebar = this.sidebarRef.current; const footer = document.querySelector("footer"); function updateSidebarPosition() { if (!sidebar || !footer) return; const footerTop = footer.getBoundingClientRect().top + window.scrollY; const sidebarHeight = sidebar.offsetHeight; const stopPoint = footerTop - sidebarHeight - 54; const scrollTop = window.scrollY; if (scrollTop >= stopPoint) { sidebar.style.position = "absolute"; sidebar.style.top = `${stopPoint + 54}px`; } else { sidebar.style.position = "fixed"; sidebar.style.top = "56px"; } } // 事件绑定与移除逻辑类似,用原生addEventListener/removeEventListener } // render中绑定ref <div ref={this.sidebarRef} id="left-sidebar"> {/* 侧边栏内容 */} </div>
内容的提问来源于stack exchange,提问作者Burak
相关产品推荐
相关产品推荐

