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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs