useListener
Listen to window events with debounce
From the Custom Hooks collection. Watches a window event and fires the
callback after a small delay, avoiding excessive updates (e.g. scroll, resize).
import { useEffect, useRef } from "react";
const useListener = (type: keyof WindowEventMap, callback: () => void, delay = 0) => {
const savedTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
const savedCallback = useRef(callback);
// Keeps the current callback without re-attaching the listener (see Custom Hooks).
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const handler = () => {
if (savedTimer.current) clearTimeout(savedTimer.current);
savedTimer.current = setTimeout(() => savedCallback.current(), delay);
};
window.addEventListener(type, handler);
return () => window.removeEventListener(type, handler);
}, [type, delay]);
};
export default useListener;
ā ļø Changes from the draft: delay = 0 by default (without it, omitting delay left
delay >= 0 false and the listener was never registered) and the portable type
ReturnType<typeof setTimeout> instead of NodeJS.Timeout.
Example ā react to scroll at most every 200 ms:
const onScroll = () => console.log(window.scrollY);
useListener("scroll", onScroll, 200);
Related: Custom Hooks Ā· use-debounce.