mrkeyoor.com_
Tue 22 Sept 18:50 UTC
npmWeb Frontendupdated 22 Sept 2026

use-debounce review

use-debounce 10.1.1 provides three React hooks. useDebounce delays a changing value, useDebouncedCallback delays a function call, and useThrottledCallback limits call frequency during continuous activity. The returned function or controls can cancel, flush, and report a waiting timer, while options cover leading execution, trailing execution, maximum wait, and value equality. Our full browser import measured 11.1 KB minified and 4.2 KB gzipped. The hooks schedule callbacks; they do not abort requests or prevent an older response from overwriting newer state.

Verdict

Our use-debounce 10.1.1 install took 0.7 seconds, used 1 MB across 2 packages, and produced a 4.2 KB gzipped browser import with no audit findings. It is a good React timer layer, but request cancellation, stale-result protection, and teardown policy remain application work.

We installed it

Lab card: what happened when we installed use-debounceScreenshot of use-debounce documentation
Install✓ · 0.7s2 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package with exports map
Browser4.2 KBgzipped (11.1 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does use-debounce install cleanly?

Yes. In a fresh container with an empty cache, npm install use-debounce finished in 0.7s, leaving 2 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does use-debounce add to a browser bundle?

4.2 KB gzipped (11.1 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does use-debounce work with both ESM and CommonJS?

Yes. Both import 'use-debounce' and require('use-debounce') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does use-debounce include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

use-debounce or lodash: which should you use?

lodash: Use its debounce when Lodash is already in the bundle and React cleanup is handled locally. Our use-debounce 10.1.1 install took 0.7 seconds, used 1 MB across 2 packages, and produced a 4.2 KB gzipped browser import with no audit findings.

When should you not use use-debounce?

The project is not built on React; its peer dependency and hook lifecycle add no value to plain JavaScript scheduling

API stability4/5The package still revolves around useDebounce, useDebouncedCallback, and useThrottledCallback with cancel, flush, pending, leading, trailing, maxWait, and equality concepts. Version 10.1.1 publishes CommonJS and ESM access through an exports map and declares one React peer. Even small scheduling changes can alter user-visible timing, so a major upgrade deserves fake-timer tests around leading, trailing, cleanup, and returned values.
Docs4/5The GitHub README returns HTTP 200 and documents delayed values, callback arguments, native listeners, cached return values, cancel, flush, isPending, maxWait, leading, trailing, equality, throttling, and server rendering. Linked sandboxes cover requests and event handlers. Several examples use older React test or rendering styles, and the page gives too little attention to aborting fetches, stale-response guards, cleanup tradeoffs, and the absence of TypeScript declarations in our measured package.
Maintenance5/5npm published 10.1.1 on March 29, 2026, and GitHub shows an unarchived repository pushed on August 5, 2026. It has 3,384 stars and 14 open issues and pull requests combined. The released package keeps zero direct dependencies and an exports map that supports CommonJS and ESM consumers. That is a solid maintenance profile for a narrow hook, though applications should still pin and test timer semantics.
Ecosystem5/5The npm downloads endpoint counted 7,501,108 downloads from August 18 through August 24, 2026. React is the sole peer dependency, and one API family covers value delay, callback debounce, throttling, cancellation, flushing, pending checks, and common timing options. Our browser import was 4.2 KB gzipped. Teams already committed to a larger hook suite may have the same primitives, making another dependency redundant despite the small payload.

Use it if

  • Search, autosave, validation, resize, scroll, or analytics work should settle after a burst of React updates
  • The component needs cancel, flush, pending state, or maxWait behavior beyond a disposable setTimeout
  • One small React package should cover delayed values, debounced callbacks, and throttled callbacks
  • Server-rendered React is required and all browser globals can remain inside client callbacks or effects
Skip it if

Setup reality

We installed use-debounce 10.1.1 in a fresh Node 22 Bookworm sandbox in 0.7 seconds. npm left 2 packages using 1 MB on disk and found zero known vulnerabilities. The package has zero direct dependencies, one React peer dependency, and 164 KB unpacked. It requires Node 16 or newer. The distribution is CommonJS with an exports map, and both require() and ESM import worked. We found no TypeScript declarations. Our browser build measured 11.1 KB minified and 4.2 KB gzipped.

No provider or configuration file is required. Choose a delayed value when rendering should follow settled state, a debounced callback when side effects should wait, or a throttled callback when work should recur during activity. useDebounce compares values with strict reference equality by default. Recreated arrays and objects therefore restart the timer; memoize them, supply equalityFn, or pass primitive arguments into a debounced callback. Event handlers should pass event.target.value rather than retain the React event object.

Unmount behavior is part of the feature contract. cancel() throws away a waiting callback, while flush() invokes it immediately. Cancelling an autosave can lose the final edit; flushing can start a request while the component is leaving. isPending() reports the internal timer, not completion of a promise returned by the eventual function. With both leading and trailing enabled, a burst may run once immediately and again after the quiet period. maxWait forces a call during continuous input.

Network ordering still needs AbortController or a monotonically increasing request ID. Debouncing reduces starts but cannot control which response finishes first. A native listener must be removed with the same debounced function reference, followed by cancel() when its trailing work is unwanted. Timer tests should use fake timers and advance them inside React act(). Server rendering support does not make window available during render, so browser reads belong inside effects or invoked callbacks.

Patterns

Keep typed and settled search text separate delay-search-value

const [query, setQuery] = useState('');
const [settledQuery] = useDebounce(query, 400);

Bind the field to query and use the 400 ms settled value only for expensive work.

Delay autosave with a maximum wait debounce-autosave

const saveDraft = useDebouncedCallback(
  (text) => api.saveDraft(text),
  750,
  { maxWait: 5000 },
);

The 5,000 ms maxWait prevents uninterrupted typing from postponing every save indefinitely.

Cancel disposable work at unmount cancel-disposable-work

useEffect(() => () => saveDraft.cancel(), [saveDraft]);

Cancellation fits suggestions or analytics that have no value after this component disappears.

Flush required work during cleanup flush-required-save

useEffect(() => () => {
  if (saveDraft.isPending()) saveDraft.flush();
}, [saveDraft]);

A flushed callback may start after teardown begins, so its request and state handling must tolerate that lifecycle.

Accept only the first rapid click run-leading-only

const submitOnce = useDebouncedCallback(submitForm, 1000, {
  leading: true,
  trailing: false,
});

This suppresses repeats within 1,000 ms in the browser, while server-side idempotency still protects retries and other tabs.

Compare meaningful object fields compare-object-value

const [filters] = useDebounce(rawFilters, 300, {
  equalityFn: (a, b) => a.query === b.query && a.sort === b.sort,
});

Without equalityFn, an equivalent newly allocated object restarts the 300 ms timer.

Throttle updates during scrolling throttle-scroll

const onScroll = useThrottledCallback(() => {
  setScrollY(window.scrollY);
}, 100);

A 100 ms throttle reports progress during the scroll; debounce would wait for scrolling to stop.

Abort the previous search request abort-old-search

const controller = useRef();
const search = useDebouncedCallback(async (query) => {
  controller.current?.abort();
  controller.current = new AbortController();
  const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal: controller.current.signal });
  setResults(await res.json());
}, 300);

The AbortController prevents a slower earlier response from replacing results for the latest query.

Detach a native listener and its timer remove-native-listener

useEffect(() => {
  window.addEventListener('resize', onResize);
  return () => {
    window.removeEventListener('resize', onResize);
    onResize.cancel();
  };
}, [onResize]);

removeEventListener needs the identical function reference, and cancel() removes its queued trailing call.

Show that a callback is waiting report-pending-state

const save = useDebouncedCallback(saveDraft, 600);
const waiting = save.isPending();

isPending() describes the 600 ms timer only; it does not track a promise returned after saveDraft starts.

Flush before a deliberate submit flush-on-explicit-submit

function submitNow() {
  saveDraft.flush();
  submitForm();
}

flush() invokes the waiting callback synchronously; coordinate promise handling if submitForm depends on the completed save.

Advance debounce time in a React test test-with-fake-timers

vi.useFakeTimers();
fireEvent.change(input, { target: { value: 'ink' } });
await act(async () => { vi.advanceTimersByTime(400); });
expect(search).toHaveBeenCalledWith('ink');

Advancing 400 ms inside act lets React process the callback-driven update before the assertion.

Alternatives

PackageRegistryPick it when
lodashnpmUse its debounce when Lodash is already in the bundle and React cleanup is handled locally
react-usenpmUse it when the application wants debouncing as part of a broad React hook collection
ahooksnpmUse it when a larger hook toolkit and request-oriented debounce helpers are already desired

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.