@pastable/react
Version:
36 lines (28 loc) • 1.09 kB
text/typescript
import { useEffect, useRef } from "react";
import { on } from "@pastable/utils";
import { useIsMountedRef } from "./useIsMounted";
/** Define an event listener on window or a given element declaratively */
export function useEvent<Data = unknown, Event extends keyof HTMLElementEventMap = any>(
event: Event,
callback: (data: Data) => void,
element: HTMLElement | Window = window
) {
const callbackRef = useRef<typeof callback>();
const offRef = useRef<Function>();
const isMountedRef = useIsMountedRef();
const safeCallbackRef = useRef(function () {
if (!isMountedRef.current) return;
callbackRef.current.apply(null, arguments);
});
useEffect(() => {
const isEqual = callback === callbackRef.current;
if (!isEqual) {
offRef.current?.();
callbackRef.current = callback;
if (callbackRef.current) {
offRef.current = on(element, event as any, safeCallbackRef.current);
}
}
return () => offRef.current?.();
}, [callback, element]);
}