我正在使用 Gatsby 。
我有这个 useEffect() Hook ,可以在文档中添加和删除事件监听器,以便我可以跟踪外部点击以关闭相应的菜单。但是当我导航到另一条路线并打开菜单时,应用程序崩溃并收到此错误:
header.js:121 Uncaught TypeError: Cannot read property 'contains' of null
at handleDropdown (header.js:121)
at HTMLDocument.<anonymous> (header.js:134)
由于我有三个事件监听器,因此每次单击任何地方都会出现三次此错误。我添加了一个控制台日志,并意识到在路由更改期间,refs 的值暂时变为空。我觉得问题是因为 header.js 卸载然后重新安装。但我添加了对 useEffect Hook 的返回,这应该删除事件监听器并在新路由加载时将它们添加回来。我上面做错了什么吗?
下面是我的函数和 useEffect Hook 。
// 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
Hook 中,则可以将相同的 Hook 局部变量传递给两个 (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>
}
关于javascript - Gatsby:事件监听器未在 React useEffects Hook 上卸载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59569247/