All files / use-throttle-callback/src useThrottleCallback.ts

100% Statements 2/2
100% Branches 4/4
100% Functions 1/1
100% Lines 2/2

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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98                                                                                                                                                                                55x     55x            
import {
  useDebounceCallback,
  type DebouncedFunction,
} from "@usefy/use-debounce-callback";
 
/**
 * Options for useThrottleCallback hook
 */
export interface UseThrottleCallbackOptions {
  /**
   * Whether to invoke on the leading edge
   * @default true
   */
  leading?: boolean;
  /**
   * Whether to invoke on the trailing edge
   * @default true
   */
  trailing?: boolean;
}
 
/**
 * Throttled function interface with control methods
 */
export type ThrottledFunction<T extends (...args: any[]) => any> =
  DebouncedFunction<T>;
 
/**
 * Creates a throttled version of the provided callback function.
 * The throttled function limits invocations to at most once per specified interval.
 * This is implemented using useDebounceCallback with maxWait set to the interval.
 *
 * @template T - The type of the callback function
 * @param callback - The function to throttle
 * @param delay - The interval in milliseconds (default: 500ms)
 * @param options - Additional options for controlling throttle behavior
 * @returns A throttled version of the callback with cancel, flush, and pending methods
 *
 * @example
 * ```tsx
 * function ScrollTracker() {
 *   const throttledScroll = useThrottleCallback(
 *     () => {
 *       console.log('Scroll position:', window.scrollY);
 *     },
 *     100
 *   );
 *
 *   useEffect(() => {
 *     window.addEventListener('scroll', throttledScroll);
 *     return () => {
 *       throttledScroll.cancel();
 *       window.removeEventListener('scroll', throttledScroll);
 *     };
 *   }, [throttledScroll]);
 *
 *   return <div>Scroll to see throttled logs</div>;
 * }
 * ```
 *
 * @example
 * ```tsx
 * // With leading edge only
 * const throttledFn = useThrottleCallback(callback, 300, { leading: true, trailing: false });
 * ```
 *
 * @example
 * ```tsx
 * // With trailing edge only
 * const throttledFn = useThrottleCallback(callback, 300, { leading: false, trailing: true });
 *
 * // Cancel pending invocation
 * throttledFn.cancel();
 *
 * // Immediately invoke pending invocation
 * throttledFn.flush();
 *
 * // Check if there's a pending invocation
 * if (throttledFn.pending()) {
 *   console.log('There is a pending call');
 * }
 * ```
 */
export function useThrottleCallback<T extends (...args: any[]) => any>(
  callback: T,
  delay: number = 500,
  options: UseThrottleCallbackOptions = {}
): ThrottledFunction<T> {
  const { leading = true, trailing = true } = options;
 
  // Throttle is implemented using debounce with maxWait set to delay
  return useDebounceCallback(callback, delay, {
    leading,
    maxWait: delay,
    trailing,
  });
}