loading...
Cover image for React Custom Hooks: useEventListener

React Custom Hooks: useEventListener

adrianbdesigns profile image Adrian Bece ・2 min read

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]);

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]
  );
};

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);

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]
  );
};

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);

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.

Posted on Sep 25 '19 by:

adrianbdesigns profile

Adrian Bece

@adrianbdesigns

React, Frontend, Magento 2 certified developer. Magento PWA Studio contributor. Rock and metal music fan. Reads Dune, sci-fi novels and Calvin & Hobbes. Creates amazing interfaces @ prototyp.digital

Discussion

markdown guide
 

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