JAVASCRIPT
Simplify Event Listener Management with `useEventListener` React Hook
Create a `useEventListener` hook to easily attach and clean up event listeners to the window, document, or a ref, preventing memory leaks and simplifying event handling.
import { useEffect, useRef } from 'react';
function useEventListener(eventType, 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 deps array ...
// ... and causing effect to re-run every render.
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
// Make sure element supports addEventListener
// On Server, window/document is undefined
const isSupported = element && element.addEventListener;
if (!isSupported) return;
// Create event listener that calls handler in a ref
const eventListener = (event) => savedHandler.current(event);
element.addEventListener(eventType, eventListener);
return () => {
element.removeEventListener(eventType, eventListener);
};
}, [eventType, element]); // Re-run if eventType or element changes
}
// Example Usage:
// function MousePositionTracker() {
// const [coords, setCoords] = useState({ x: 0, y: 0 });
// const updateMousePosition = useCallback((event) => {
// setCoords({ x: event.clientX, y: event.clientY });
// }, []); // memoize handler to prevent infinite loop
// useEventListener('mousemove', updateMousePosition);
// return (
// <p>
// Mouse X: {coords.x}, Y: {coords.y}
// </p>
// );
// }
// To use with a ref:
// function MyDiv() {
// const divRef = useRef();
// useEventListener('click', () => console.log('Div clicked!'), divRef.current);
// return <div ref={divRef}>Click me</div>;
// }
How it works: The `useEventListener` hook simplifies adding and removing event listeners from the DOM, defaulting to the `window` object. It ensures that listeners are properly cleaned up when the component unmounts or dependencies change, preventing memory leaks. It also uses a `useRef` to maintain a stable reference to the event handler, avoiding unnecessary re-registrations of the listener.