How do I window removeEventListener using React useEffect
You can put the handleKeyUp
function inside of the function given to useEffect
(which is the recommended way of doing it according to the official documentation) and only add the listener and return a cleanup function when collapsed
is false.
useEffect(() => {
if (collapsed) {
return;
}
function handleKeyUp(event) {
switch (event.key) {
case "Escape":
setCollapsed(true);
break;
}
}
window.addEventListener("keyup", handleKeyUp);
return () => window.removeEventListener("keyup", handleKeyUp);
}, [collapsed]);
Tholle's answer may work, but it's bad practice to declare a function inside an if
.
It makes it harder to follow when the function is declared and when it is not. Also it can lead to bugs because functions are hoisted up.
There's a neater way to fix it:
By wrapping your event handler with the useCallback hook.
const [collapsed, setCollapsed] = useState(true)
const handleKeyUp = useCallback((event) => {
if (event.key === "Escape") {
setCollapsed(true)
}
}, [setCollapsed])
useEffect(() => {
if (!collapsed) {
window.addEventListener("keyup", handleKeyUp)
} else {
window.removeEventListener("keyup", handleKeyUp)
}
return () => window.removeEventListener("keyup", handleKeyUp)
}, [collapsed, handleKeyUp])
useCallback
has a dependency onsetCollapsed
. This makes surehandleKeyUp
is not redefined when the component rerenders (which always happens when state changes)useEffect
will conditionally add/remove the event listener, otherwise events will keep firing as long as the component is mounted.
If you use a lot of event handlers in useEffect, there's a custom hook for that: https://usehooks.com/useEventListener/
Here's the question posters example updated with my solution: https://codepen.io/publicJorn/pen/eYzwENN