All files / hooks useDebounce.ts

92.85% Statements 13/14
75% Branches 3/4
100% Functions 6/6
92.85% Lines 13/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70                                                                    5x 5x     5x 5x       5x 5x 5x           5x     14x 9x       14x 5x 5x                
/**
 * useDebounce Hook
 * 
 * Debounces a function to execute only after a delay since the last call.
 * Useful for search inputs, resize handlers, and other delayed actions.
 * 
 * Uses a ref pattern to ensure the latest callback is always called
 * without recreating the debounced function on every render.
 * 
 * @module hooks/useDebounce
 * @category Performance
 * @korean 디바운스 훅
 */
 
import { useCallback, useRef, useLayoutEffect, useEffect } from 'react';
 
/**
 * Hook to debounce a callback function
 * 
 * @param callback - Function to debounce
 * @param delay - Delay in milliseconds before execution
 * @returns Debounced function
 * 
 * @example
 * ```tsx
 * const handleSearch = useDebounce((query: string) => {
 *   // Perform search
 * }, 300);
 * ```
 */
export function useDebounce<T extends (...args: unknown[]) => void>(
  callback: T,
  delay: number
): (...args: Parameters<T>) => void {
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);
  const callbackRef = useRef(callback);
  
  // Keep callback ref up to date
  useLayoutEffect(() => {
    callbackRef.current = callback;
  });
  
  // Cleanup on unmount
  useEffect(() => {
    return () => {
      Iif (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []);
 
  return useCallback(
    (...args: Parameters<T>) => {
      // Clear existing timeout
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
 
      // Set new timeout
      timeoutRef.current = setTimeout(() => {
        callbackRef.current(...args);
        timeoutRef.current = null;
      }, delay);
    },
    [delay]
  );
}
 
export default useDebounce;