useEventListener(๐Ÿ‘‚)

August 02, 2020ย ย โ€ขย ย 1 min read

#2 hook of the week

To remind you of the purpose and goal of this week:

For a whole week I'll post a new hook every day. All hooks will support Server-Side Rendering (SSR) and have TypeScript implemented.

I will not describe the hooks in great detail, I'll just present them and show how it's implemented. Then you can do whatever you want with them.

Every hook is also available here, together with a range of other hooks.

View source

The hook ๐ŸŽฃ

With this hook you can easily add event listeners and it will remove itself to avoid memory leaks. Element supports refs, document and window.

I'm using my isSSR and getElement() utility.

import { useRef, useEffect, RefObject, useCallback } from 'react';
import { isSSR, getElement } from './utils';

interface Props {
  type: keyof WindowEventMap;
  listener: EventListener;
  element?: RefObject<Element> | Document | Window;
  options?: AddEventListenerOptions;
}

export const useEventListener = ({
  type,
  listener,
  element = isSSR ? undefined : window,
  options
}: Props) => {
  const savedListener = useRef<EventListener>();

  useEffect(() => {
    savedListener.current = listener;
  }, [listener]);

  const handleEventListener = useCallback((event: Event) => {
    savedListener.current?.(event);
  }, []);

  useEffect(() => {
    const target = getElement(element);
    target?.addEventListener(type, handleEventListener, options);
    return () => target?.removeEventListener(type, handleEventListener);
  }, [type, element, options, handleEventListener]);
};

Usage

Just a simple showcase that console.log() the event when a user clicks on the element. If we wouldn't pass an element it would fallback to the window.

import React from 'react';
import { useEventListener } from './useEventListener';

const Component = () => {
  const ref = useRef(null);

  useEventListener({
    element: ref,
    type: 'click',
    listener: (event) => console.log(event),
    options: { passive: true }
  });

  return <div ref={ref} />;
};

export default Component;

The end ๐Ÿ‘‚

I hope you found this helpful.