← Back to all snippets
JAVASCRIPT

Safely Manage Event Listeners with useEventListener Hook

A flexible React hook to abstract away the complexity of adding and removing event listeners, ensuring proper cleanup and preventing memory leaks.

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's dependency array.
  useEffect(() => {
    savedHandler.current = handler;
  }, [handler]);

  useEffect(() => {
    // Make sure element supports addEventListener
    // On another note, window object is not available on SSR
    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(eventType, eventListener);

    // Remove event listener on cleanup
    return () => {
      element.removeEventListener(eventType, eventListener);
    };
  }, [eventType, element]); // Re-run if eventType or element changes

  return null;
}

export default useEventListener;

// Example Usage:
// function MyComponent() {
//   const handleScroll = () => {
//     console.log('Window scrolled!', window.scrollY);
//   };
//   useEventListener('scroll', handleScroll);

//   const myRef = useRef();
//   const handleClick = () => {
//     console.log('Element clicked!');
//   };
//   useEventListener('click', handleClick, myRef.current); // Attaching to a specific element
//   return <div ref={myRef} style={{ height: '200px', overflow: 'scroll' }}>Scrollable Content</div>;
// }
How it works: The `useEventListener` hook simplifies the process of attaching and detaching event listeners to the `window`, `document`, or specific DOM elements. It ensures that listeners are properly cleaned up when the component unmounts or when the event type or target element changes, preventing memory leaks and making event management declarative in React.

Need help integrating this into your project?

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

Hire DigitalCodeLabs