Subscribe to window or document events with automatic cleanup on unmount. No stale closures.
import { useEffect, RefObject } from 'react';
export function useEventListener<K extends keyof WindowEventMap>(
target: RefObject<EventTarget | null> | EventTarget | null,
event: K,
handler: (e: WindowEventMap[K]) => void,
options?: boolean | AddEventListenerOptions
): void {
useEffect(() => {
const el = target && 'current' in target ? target.current : target;
if (!el) return;
el.addEventListener(event, handler as EventListener, options);
return () => el.removeEventListener(event, handler as EventListener, options);
}, [target, event, handler, options]);
}Paste into your hooks folder. Pass a ref (element ref) or a direct EventTarget (e.g. window).
Listen to resize or keydown with automatic cleanup when the component unmounts.
useEventListener(window, 'resize', handleResize);