use-debounce-pro

A lightweight React hook for debouncing and throttling with advanced features


Keywords
react, hook, debounce, throttle, performance, typescript
License
MIT
Install
npm install use-debounce-pro@1.0.0

Documentation

use-debounce-pro

npm version bundle size license TypeScript

A tiny (759B gzipped) React hook for debouncing and throttling โ€” with full control.

Features

  • โšก Tiny โ€” 759 bytes gzipped, zero dependencies
  • ๐ŸŽฏ Dual mode โ€” Debounce and throttle in one hook
  • ๐Ÿ”„ Edge control โ€” Leading, trailing, or both
  • โฑ๏ธ Max wait โ€” Guarantee execution within a time window
  • ๐ŸŽฎ Full control โ€” cancel(), flush(), isPending()
  • ๐Ÿ’ช TypeScript โ€” Strict types with full generic inference
  • ๐Ÿงน Safe โ€” Automatic cleanup on unmount, no stale closures

Installation

npm install use-debounce-pro
yarn add use-debounce-pro
pnpm add use-debounce-pro

Quick Start

import { useDebouncePro } from "use-debounce-pro";

function SearchBox() {
  const debouncedSearch = useDebouncePro(
    (query: string) => fetchResults(query),
    300,
  );

  return <input onChange={(e) => debouncedSearch(e.target.value)} />;
}

API

useDebouncePro(callback, options)

The primary hook. Returns a debounced/throttled function with control methods attached.

const debouncedFn = useDebouncePro(callback, 300);
// or
const debouncedFn = useDebouncePro(callback, { wait: 300, leading: true });

debouncedFn("arg"); // Call the debounced function
debouncedFn.cancel(); // Cancel pending execution
debouncedFn.flush(); // Execute pending call immediately
debouncedFn.isPending(); // Check if a call is pending

useDebouncedCallback(callback, options)

Alternative API that returns an object with named methods.

const { run, cancel, flush, isPending } = useDebouncedCallback(
  (query: string) => searchAPI(query),
  { wait: 300 },
);

return <input onChange={(e) => run(e.target.value)} />;

Options

Option Type Default Description
wait number 0 Delay in milliseconds
mode "debounce" | "throttle" "debounce" Operation mode
leading boolean false Execute on the leading edge
trailing boolean true Execute on the trailing edge
maxWait number undefined Max time a call can be delayed

When passing a number instead of an options object, it is used as the wait value with default settings.

Return Value

Method Type Description
(โ€ฆargs) (...args) => ReturnType | undefined The debounced function
.cancel() () => void Cancel any pending invocation
.flush() () => ReturnType | undefined Immediately execute pending call
.isPending() () => boolean Whether a call is pending

Common Patterns

Search Input

Debounce API calls while the user types:

function Search() {
  const [results, setResults] = useState([]);

  const search = useDebouncePro(async (query: string) => {
    const data = await fetch(`/api/search?q=${query}`);
    setResults(await data.json());
  }, 300);

  return <input onChange={(e) => search(e.target.value)} />;
}

Scroll Handler

Throttle scroll events for performance:

function InfiniteScroll() {
  const handleScroll = useDebouncePro(
    () => {
      const { scrollTop, scrollHeight, clientHeight } =
        document.documentElement;
      if (scrollTop + clientHeight >= scrollHeight - 200) {
        loadMore();
      }
    },
    { wait: 100, leading: true, trailing: true, maxWait: 100 },
  );

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, [handleScroll]);
}

Form Auto-Save

Save drafts as the user edits:

function Editor() {
  const autoSave = useDebouncePro((content: string) => saveDraft(content), {
    wait: 1000,
    maxWait: 5000,
  });

  return (
    <textarea
      onChange={(e) => autoSave(e.target.value)}
      onBlur={() => autoSave.flush()}
    />
  );
}

Window Resize

Recalculate layout on resize without jank:

function ResponsiveChart() {
  const recalc = useDebouncePro(() => {
    setDimensions({
      width: window.innerWidth,
      height: window.innerHeight,
    });
  }, 150);

  useEffect(() => {
    window.addEventListener("resize", recalc);
    return () => window.removeEventListener("resize", recalc);
  }, [recalc]);
}

Comparison

Feature use-debounce-pro use-debounce lodash.debounce
Gzipped size 759B ~1.4KB ~5.3KB
Debounce โœ… โœ… โœ…
Throttle โœ… โŒ (separate hook) โŒ (separate fn)
Leading/trailing โœ… โœ… โœ…
maxWait โœ… โœ… โœ…
cancel / flush โœ… โœ… โœ…
isPending โœ… โŒ โŒ
React hook โœ… โœ… โŒ
TypeScript โœ… (strict) โœ… โš ๏ธ @types
Zero dependencies โœ… โœ… โŒ
Tree-shakeable โœ… โœ… โŒ

TypeScript

Full generic inference โ€” your argument and return types are preserved:

// Types are inferred automatically
const debouncedSearch = useDebouncePro(
  (query: string, page: number) => fetchResults(query, page),
  300,
);

debouncedSearch("hello", 1); // โœ… type-safe
debouncedSearch(123); // โŒ type error

Requirements

  • React โ‰ฅ 16.8.0 (hooks support)

License

MIT