14114
11/18/2025
import { useEffect, useRef } from 'react';
interface UseDebounceWithCleanupOptions { delay?: number; // Automatically handles pending requests on unmount. // Use shouldFlush for immediate execution on specific conditions. shouldFlush?: boolean; }
interface UseDebounceWithCleanupParams { callback: () => void; options?: UseDebounceWithCleanupOptions; }
export const useDebounceWithCleanup = ( { callback, options = {} }: UseDebounceWithCleanupParams, dependency: readonly unknown[] ) => { const { delay = 500, shouldFlush = false } = options; const timeoutRef = useRef<number | null>(null); const callbackRef = useRef(callback); const hasPendingRef = useRef(false);
useEffect(() => { callbackRef.current = callback; }, [callback]);
useEffect(() => { if (shouldFlush && timeoutRef.current) { clearTimeout(timeoutRef.current); callbackRef.current(); timeoutRef.current = null; hasPendingRef.current = false; } }, [shouldFlush]);
useEffect(() => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); }
timeoutRef.current = window.setTimeout(() => {
callbackRef.current();
timeoutRef.current = null;
hasPendingRef.current = false;
}, delay);
hasPendingRef.current = true;
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [...dependency, delay]);
useEffect(() => { return () => { if (timeoutRef.current && hasPendingRef.current) { clearTimeout(timeoutRef.current); callbackRef.current(); timeoutRef.current = null; hasPendingRef.current = false; } }; }, []); };
