all repos — caroster @ 832452704d5eae9e2164e58c086cdf365e51e5e7

[Octree] Group carpool to your event https://caroster.io

frontend/hooks/useEventListener.ts (view raw)

 1import { RefObject, useEffect, useRef } from 'react'
 2import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'
 3
 4// Window Event based useEventListener interface
 5function useEventListener<K extends keyof WindowEventMap>(
 6  eventName: K,
 7  handler: (event: WindowEventMap[K]) => void,
 8  element?: undefined,
 9  options?: boolean | AddEventListenerOptions,
10): void
11
12// Element Event based useEventListener interface
13function useEventListener<
14  K extends keyof HTMLElementEventMap,
15  T extends HTMLElement = HTMLDivElement,
16>(
17  eventName: K,
18  handler: (event: HTMLElementEventMap[K]) => void,
19  element: RefObject<T>,
20  options?: boolean | AddEventListenerOptions,
21): void
22
23// Document Event based useEventListener interface
24function useEventListener<K extends keyof DocumentEventMap>(
25  eventName: K,
26  handler: (event: DocumentEventMap[K]) => void,
27  element: RefObject<Document>,
28  options?: boolean | AddEventListenerOptions,
29): void
30
31function useEventListener<
32  KW extends keyof WindowEventMap,
33  KH extends keyof HTMLElementEventMap,
34  T extends HTMLElement | void = void,
35>(
36  eventName: KW | KH,
37  handler: (
38    event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event,
39  ) => void,
40  element?: RefObject<T>,
41  options?: boolean | AddEventListenerOptions,
42) {
43  // Create a ref that stores handler
44  const savedHandler = useRef(handler)
45
46  useIsomorphicLayoutEffect(() => {
47    savedHandler.current = handler
48  }, [handler])
49
50  useEffect(() => {
51    // Define the listening target
52    const targetElement: T | Window = element?.current || window
53    if (!(targetElement && targetElement.addEventListener)) {
54      return
55    }
56
57    // Create event listener that calls handler function stored in ref
58    const eventListener: typeof handler = event => savedHandler.current(event)
59
60    targetElement.addEventListener(eventName, eventListener, options)
61
62    // Remove event listener on cleanup
63    return () => {
64      targetElement.removeEventListener(eventName, eventListener)
65    }
66  }, [eventName, element, options])
67}
68
69export default useEventListener