UIKit/lib/hooks/useEventListener.ts
2023-08-14 15:03:23 +03:00

80 lines
2.6 KiB
TypeScript

import { useEffect, useRef, RefObject, useLayoutEffect } from "react";
// https://usehooks-ts.com/react-hook/use-event-listener
// MediaQueryList Event based useEventListener interface
export function useEventListener<K extends keyof MediaQueryListEventMap>(
eventName: K,
handler: (event: MediaQueryListEventMap[K]) => void,
element: RefObject<MediaQueryList>,
options?: boolean | AddEventListenerOptions,
): void;
// Window Event based useEventListener interface
export function useEventListener<K extends keyof WindowEventMap>(
eventName: K,
handler: (event: WindowEventMap[K]) => void,
element?: undefined,
options?: boolean | AddEventListenerOptions,
): void;
// Element Event based useEventListener interface
export function useEventListener<
K extends keyof HTMLElementEventMap,
T extends HTMLElement = HTMLDivElement,
>(
eventName: K,
handler: (event: HTMLElementEventMap[K]) => void,
element: RefObject<T>,
options?: boolean | AddEventListenerOptions,
): void;
// Document Event based useEventListener interface
export function useEventListener<K extends keyof DocumentEventMap>(
eventName: K,
handler: (event: DocumentEventMap[K]) => void,
element: RefObject<Document>,
options?: boolean | AddEventListenerOptions,
): void;
export function useEventListener<
KW extends keyof WindowEventMap,
KH extends keyof HTMLElementEventMap,
KM extends keyof MediaQueryListEventMap,
T extends HTMLElement | MediaQueryList | void = void,
>(
eventName: KW | KH | KM,
handler: (
event:
| WindowEventMap[KW]
| HTMLElementEventMap[KH]
| MediaQueryListEventMap[KM]
| Event,
) => void,
element?: RefObject<T>,
options?: boolean | AddEventListenerOptions,
) {
// Create a ref that stores handler
const savedHandler = useRef(handler);
useLayoutEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
// Define the listening target
const targetElement: T | Window = element?.current ?? window;
if (!(targetElement && targetElement.addEventListener)) return;
// Create event listener that calls handler export function stored in ref
const listener: typeof handler = event => savedHandler.current(event);
targetElement.addEventListener(eventName, listener, options);
// Remove event listener on cleanup
return () => {
targetElement.removeEventListener(eventName, listener, options);
};
}, [eventName, element, options]);
}