UNPKG

@react-hookz/web

Version:

React hooks done right, for browser and SSR.

50 lines (49 loc) 1.95 kB
import { useEffect, useMemo } from 'react'; import { useIsMounted } from '../useIsMounted/index.js'; import { useSyncedRef } from '../useSyncedRef/index.js'; import { hasOwnProperty, off, on } from '../util/misc.js'; /** * An HTML element or ref object containing an HTML element. * * @param target An HTML element or ref object containing an HTML element. * @param params Parameters specific to the target element's `addEventListener` method. Commonly * something like `[eventName, listener, options]`. */ export function useEventListener(target, ...params) { const isMounted = useIsMounted(); // Create static event listener const listenerRef = useSyncedRef(params[1]); const eventListener = useMemo(() => // As some event listeners designed to be used through `this` // it is better to make listener a conventional function as it // infers call context function (...args) { if (!isMounted()) { return; } // We dont care if non-listener provided, simply dont do anything if (typeof listenerRef.current === 'function') { listenerRef.current.apply(this, args); } else if (typeof listenerRef.current.handleEvent === 'function') { listenerRef.current.handleEvent.apply(this, args); } }, // eslint-disable-next-line react-hooks/exhaustive-deps []); useEffect(() => { const tgt = isRefObject(target) ? target.current : target; if (!tgt) { return; } const restParams = params.slice(2); on(tgt, params[0], eventListener, ...restParams); return () => { off(tgt, params[0], eventListener, ...restParams); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [target, params[0]]); } function isRefObject(target) { return target !== null && typeof target === 'object' && hasOwnProperty(target, 'current'); }