JAVASCRIPT
Attach and Cleanup Event Listeners with `useEventListener`
Discover how to create a robust `useEventListener` React hook to easily attach global event listeners to the window, document, or a DOM element with automatic cleanup.
import { useEffect, useRef } from 'react';
function useEventListener(eventName, handler, element = window) {
// Create a ref that stores handler
const savedHandler = useRef();
// Update ref.current value if handler changes.
// This allows our effect below to always get latest handler ...
// ... without us needing to pass it in effect's dependency array.
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
// Make sure element supports addEventListener
// On Server, window is undefined
const isSupported = element && element.addEventListener;
if (!isSupported) return;
// Create event listener that calls handler function stored in ref
const eventListener = (event) => savedHandler.current(event);
// Add event listener
element.addEventListener(eventName, eventListener);
// Clean up on unmount
return () => {
element.removeEventListener(eventName, eventListener);
};
}, [eventName, element]); // Re-run if eventName or element changes
return savedHandler;
}
export default useEventListener;
// Example Usage:
// import React, { useRef } from 'react';
// function MyComponent() {
// const handleScroll = () => {
// console.log('Window scrolled!', window.scrollY);
// };
//
// useEventListener('scroll', handleScroll, typeof window !== 'undefined' ? window : null);
//
// const myDivRef = useRef();
// const handleClickDiv = () => {
// console.log('Div clicked!');
// };
// // Ensure myDivRef.current is available when attaching listener
// useEventListener('click', handleClickDiv, myDivRef.current);
//
// return <div ref={myDivRef} style={{ height: '200px', width: '200px', border: '1px solid black', overflow: 'auto' }}>
// Scroll me or click me
// </div>;
// }
How it works: The `useEventListener` hook provides a clean way to attach event listeners to the `window`, `document`, or a specific DOM element, with automatic cleanup when the component unmounts. It uses a `useRef` to store the latest event handler function, preventing unnecessary re-creation of the event listener if only the handler changes, and an `useEffect` to manage the lifecycle of adding and removing the listener, ensuring proper resource management.