我正在使用盖茨比。
我有这个useEffect((钩子,它可以在文档中添加和删除事件侦听器,因此我可以跟踪外部单击以关闭相应的菜单。但是当我导航到另一条路线并打开菜单时,应用程序中断,我收到此错误:
header.js:121 Uncaught TypeError: Cannot read property 'contains' of null
at handleDropdown (header.js:121)
at HTMLDocument.<anonymous> (header.js:134)
每次单击任何地方时,我都会收到此错误三次,因为我有三个事件侦听器。我添加了一个控制台日志,并意识到在路由更改期间,引用的值暂时变为空。我觉得问题是因为标题.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)
}
}, [])
在JavaScript中,函数通过引用进行比较。这意味着() => {} !== () => {}
.当您尝试删除useEffect
清理回调中的事件侦听器时,您会传递新定义的函数,但由于上述原因,它们与您定义的现有处理程序不匹配。
如果重构代码以将事件处理程序包含在useEffect
钩子中,则可以将相同的钩子局部变量传递给两个(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>
}