DEV Community

Cover image for React Custom Hooks: useEventListener
Adrian Bece
Adrian Bece

Posted on

React Custom Hooks: useEventListener

This is a really simple and straightforward, but also a really useful custom hook. This custom React hook takes care of setting up the event listener on a component mount and removing the listener on component unmount.

addEventListener and removeEventListener

Let's take a look at the addEventListener and removeEventListener function definitions so we can see what parameters we need to pass to the custom hook in order to make it flexible for all use-cases.

target.addEventListener(type, listener[, options]);
target.removeEventListener(type, listener[, options]);
Enter fullscreen mode Exit fullscreen mode

From the definitions, we can see that both functions use the following parameters: target,type, listener and options. Now that we've established the input parameters, we can go ahead and create our hook.

Custom hook

import { useEffect } from 'react';

const useEventListener = (target, type, listener, ...options) => {
  React.useEffect(
    () => {
      target.addEventListener(type, listener, ...options);
      return () => {
        target.removeEventListener(type, listener, ...options);
      };
    },
    [target, type, listener, options]
  );
};
Enter fullscreen mode Exit fullscreen mode

We use useEffect React hook to take care of what is happening on component mount and unmount. If you want to know more about useEffect hook, I've covered it in detail here:

This is how we initiate our hook in another component (for example, we are listening to window resize event).

useEventListener(window, 'resize', handleWindowResize);
Enter fullscreen mode Exit fullscreen mode

This hook works well if we pass a document or window or object. If that's going to be the use case for our custom hook, then we can leave it as it is. However, if we intend to pass refs, this custom hook will need some small modifications in order to also work with refs.

Adding ref functionality

import { useEffect } from 'react';

const useEventListener = (target, type, listener, ...options) => {
  React.useEffect(
    () => {
      const targetIsRef = target.hasOwnProperty("current");
      const currentTarget = targetIsRef ? target.current : target;
      if (currentTarget)
        currentTarget.addEventListener(type, listener, ...options);
      return () => {
        if (currentTarget)
          currentTarget.removeEventListener(type, listener, ...options);
      };
    },
    [target, type, listener, options]
  );
};
Enter fullscreen mode Exit fullscreen mode

Inside the useEffect hook, we are checking if the passed target is a ref or a window or a document element.

This is how we are initializing our hook (we can initialize as many listeners as we need in the same component):

// Window resize listener
useEventListener(window, 'resize', handleWindowResize);

// You can also pass refs
const elementRef = useRef(null);
useEventListener(elementRef, 'mousedown', handleElementClick);
Enter fullscreen mode Exit fullscreen mode

Codepen example


Thank you for taking the time to read this post. If you've found this useful, please give it a ❤️ or 🦄, share and comment.

Top comments (1)

Collapse
 
patrikneunteufel profile image
PatrikNeunteufel

why you call React.useEffect when you import {useEffect} from 'react' ?