A tiny (759B gzipped) React hook for debouncing and throttling โ with full control.
- โก 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
npm install use-debounce-proyarn add use-debounce-propnpm add use-debounce-proimport { useDebouncePro } from "use-debounce-pro";
function SearchBox() {
const debouncedSearch = useDebouncePro(
(query: string) => fetchResults(query),
300,
);
return <input onChange={(e) => debouncedSearch(e.target.value)} />;
}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 pendingAlternative 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)} />;| 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.
| 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 |
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)} />;
}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]);
}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()}
/>
);
}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]);
}| 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) | โ |
|
| Zero dependencies | โ | โ | โ |
| Tree-shakeable | โ | โ | โ |
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- React โฅ 16.8.0 (hooks support)