react-enhanced-debounce-hook
v1.0.10
Published
A tiny, dependency-free React hook library for debouncing values and state. Includes two ergonomic APIs so you can pick the pattern that fits your use-case:
Maintainers
Readme
react-enhanced-debounce-hook
A tiny, dependency-free React hook library for debouncing values and state. Includes two ergonomic APIs so you can pick the pattern that fits your use-case:
useDebounce(value, delay?, options?)— API-compatible withuse-debounce(returns debounced value + controls).useDebounceState(initial, delay?)— single-hook UX that returns immediate value, setter, debounced value, and controls (no need for two local states).
Perfect for search inputs, typeaheads, autosave, preventing noisy API calls, and improving UI responsiveness.
Install
npm install react-enhanced-debounce-hook
# or
yarn add react-enhanced-debounce-hooksimple usage example in CodeSandbox: https://codesandbox.io/p/sandbox/8vxv8j
Usage
useDebounceState(initial, delay?)
import React, { useEffect } from "react";
import { useDebounceState } from "react-enhanced-debounce-hook";
function SearchBox() {
const [value, setValue, debouncedValue] = useDebounceState("", 300);
useEffect(() => {
if (debouncedValue) {
console.log("Trigger API call with:", debouncedValue);
// fetch(`/api/search?q=${debouncedValue}`)
}
}, [debouncedValue]);
return (
<div>
<input
type="text"
placeholder="Search..."
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<p>Immediate: {value}</p>
<p>Debounced (after 300ms): {debouncedValue}</p>
</div>
);
}useDebounce(value, delay?, options?)
import React, { useState } from "react";
import { useDebounce } from "react-enhanced-debounce-hook";
export default function DemoUseDebounce() {
const [text, setText] = useState("Hello");
// const [debouncedText, controls] = useDebounce(text, 1000);
const [debouncedText] = useDebounce(text, 1000);
return (
<div style={{ padding: 20, fontFamily: "Arial" }}>
<h3>useDebounce demo</h3>
<input
value={text}
onChange={(e) => setText(e.target.value)}
style={{ padding: 8, width: 320 }}
/>
<div style={{ marginTop: 8 }}>
<div>
Actual value: <b>{text}</b>
</div>
<div>
Debounced value: <b>{debouncedText}</b>
</div>
</div>
{/* <div style={{ marginTop: 8 }}>
<button onClick={() => controls.flush()}>Flush (apply now)</button>
<button onClick={() => controls.cancel()} style={{ marginLeft: 8 }}>
Cancel pending
</button>
</div> */}
</div>
);
}
API Reference
useDebounce(value, delay?, options?)
value: any value to debounce
delay: debounce time in ms (default:
500)options:
leading: trigger immediately on the first calltrailing: trigger after the delay (default:true)
Returns: [debouncedValue, controls]
debouncedValue— the debounced version of your valuecontrols—{ cancel, flush }to cancel or force flush
useDebounceState(initial, delay?)
- initial: initial state value
- delay: debounce time in ms
Returns: [value, setValue, debouncedValue, controls]
value— the immediate state (updates instantly)setValue— setter functiondebouncedValue— debounced state (updates after delay)controls—{ cancel, flush }
When to Use Which?
- Use
useDebounceif you already manage your own state. - Use
useDebounceStateif you want a single hook to handle both immediate and debounced state without boilerplate.
License
MIT © 2025
