Debounce is a technique used to improve the performance of frequently executed actions, by delaying them, grouping them, and only executing the last call.
Imagine, Say for example, You need a search input that automatically queries results as you type.
You don't want to call the backend or API's with every keystroke, instead you only observe the final value. This is the perfect use for the debounce function, and in fact, it's the most common one.
Define basic debounce function with Javascript
Debounce is implemented using a timer, where the action executes only after the timeout. If the action is repeated before the timer has expires, we restart the timer.
function debounce(func, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
In the debounce function:
- func is the original function you want to debounce.
- delay is the time in milliseconds that you want to wait after the last call before invoking the original function.
Implement the debounce function
Create a function that accepts a function to debounce and the timeout delay as arguments.
const updateOptions = debounce(query => {
fetch(`https://dummyjson.com/products/search?q=${query}`)
.then(res => res.json())
.then(data => setOptions(data))
}, 1000)
input.addEventListener("input", e => {
updateOptions(e.target.value)
)}
Implement the debounce function with React
export default function SearchBox() {
const [search, setSearch] = React.useState("");
const [result, setResult] = React.useState([]);
const handleChange = (e) => {
setSearch(e.target.value);
};
let timeout;
const handleSearch = async (query) => {
setResult([]);
if (query.length < 3) {
return null;
}
const response = await fetch(
`https://dummyjson.com/products/search?q=${query}`
);
const { products } = await response.json();
setResult(products);
};
React.useEffect(() => {
clearTimeout(timeout);
timeout = setTimeout(() => {
handleSearch(search);
}, 500);
return () => clearTimeout(timeout);
}, [search]);
return (
<>
<div className="mb-3 m-11">
<div className="relative mb-4 flex w-full flex-wrap items-stretch">
<form>
<label
htmlFor="default-search"
className="mb-2 text-sm font-medium text-gray-900
sr-only dark:text-white"
>
Search
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 flex items-center
pl-3 pointer-events-none">
<svg
className="w-4 h-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 20"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
/>
</svg>
</div>
<input
type="search"
id="default-search"
className="block w-full p-4 pl-10 text-sm text-gray-900
border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500
focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600
dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500
dark:focus:border-blue-500"
placeholder="Search Mockups, Logos..."
value={search}
onChange={handleChange}
/>
</div>
</form>
</div>
</div>
<div className="mb-3 m-11">
{result.map((item) => (
<div className="text-xl">{item.title}</div>
))}
</div>
</>
);
}
the useEffect runs every time the input value changes, after which there is a delay of 500 milliseconds, then the value result is updated with search value.
The Result will be
Happy Coding...😀