我正在使用盖茨比。
我有这个useEffect()钩子,用于在文档中添加和删除事件监听器,因此我可以跟踪外部点击以关闭相应菜单。但是,当我导航到另一条路线并打开菜单时,应用程序中断,并且出现此错误:
header.js:121 Uncaught TypeError: Cannot read property 'contains' of null
at handleDropdown (header.js:121)
at HTMLDocument.<anonymous> (header.js:134)
我有3个事件侦听器,因此每次在任何地方单击都会出现此错误三次。我添加了一个控制台日志,并意识到在路由更改期间,ref的值会暂时变为空。我觉得问题是因为header.js卸载然后重新安装。但是我在useEffect钩子中添加了一个返回值,该钩子应该删除事件侦听器,并在加载新路由时将其添加回去。我在上面做错了什么吗?
下面是我的功能和useEffect钩子。
// Function to close menus on outside clicks
const handleDropdown = (menuRef, buttonRef, handler, e) => {
console.log(!!menuRef.current, !!buttonRef.current)
if (
menuRef.current.contains(e.target) ||
buttonRef.current.contains(e.target)
) {
return
}
handler(false)
}
useEffect(() => {
document.addEventListener("mousedown", e =>
handleDropdown(mobileMenuRef, menuButtonRef, setShowMobileMenu, e)
)
document.addEventListener("mousedown", e =>
handleDropdown(coursesMenuRef, coursesButtonRef, setShowCoursesMenu, e)
)
document.addEventListener("mousedown", e =>
handleDropdown(
schedulesMenuRef,
schedulesButtonRef,
setShowSchedulesMenu,
e
)
)
document.addEventListener("scroll", handleFixedNavbar)
return () => {
document.removeEventListener("mousedown", e =>
handleDropdown(mobileMenuRef, menuButtonRef, setShowMobileMenu, e)
)
document.removeEventListener("mousedown", e =>
handleDropdown(coursesMenuRef, coursesButtonRef, setShowCoursesMenu, e)
)
document.removeEventListener("mousedown", e =>
handleDropdown(
schedulesMenuRef,
schedulesButtonRef,
setShowSchedulesMenu,
e
)
)
document.removeEventListener("scroll", handleFixedNavbar)
}
}, [])
答案 0 :(得分:1)
在JavaScript中,功能通过引用进行比较。这意味着() => {} !== () => {}
。当您尝试在useEffect
清理回调中删除事件侦听器时,您将传递新定义的函数,但是由于上述原因,它们将与您定义的现有处理程序不匹配。
如果您重构代码以在useEffect
挂钩中包含事件处理程序,则可以将相同的hook-local变量传递给两个(add|remove)EventListener
调用:
const useOnClickOutside = (refs, callback) => {
useEffect(() => {
const eventHandler = e => {
if (refs.some(ref => ref.current.contains(e.target))) {
return
} else {
callback(false)
}
}
document.addEventListener("mousedown", eventHandler)
return () => {
document.removeEventListener("mousedown", eventHandler)
}
}, [refs, callback])
}
const YourComponent = () => {
const someRef = useRef()
const someOtherRef = useRef()
useOnClickOutside([someRef, someOtherRef], () => {
console.log("Click outside happened!")
})
return <div>Some Content</div>
}