A simple, dependency-free debounce utility for React, Solid, Svelte, Vue, and vanilla JavaScript with async support.
For those who like simple things: https://use-simple-debounce.jujiplay.com/
setTimeout for reliable debouncingnpm install use-simple-debounce
import { useDebounce } from 'use-simple-debounce';
function SearchComponent() {
const debounced = useDebounce();
const handleSearch = (query: string) => {
debounced(() => {
// This will only execute 300ms after the user stops typing
performSearch(query);
}, 300);
};
return (
<input type="text" onChange={(e) => handleSearch(e.target.value)} placeholder="Search..." />
);
}
import { createSignal } from 'solid-js';
import { createDebounce } from 'use-simple-debounce/solid';
function SearchComponent() {
const [query, setQuery] = createSignal('');
const debounced = createDebounce();
const handleSearch = (value: string) => {
setQuery(value);
debounced(() => {
// This will only execute 300ms after the user stops typing
performSearch(value);
}, 300);
};
return (
<input
type="text"
value={query()}
onInput={(e) => handleSearch(e.target.value)}
placeholder="Search..."
/>
);
}
<script>
import { createDebounce } from 'use-simple-debounce/svelte';
let query = '';
const debounced = createDebounce();
function handleSearch(value) {
query = value;
debounced(() => {
// This will only execute 300ms after the user stops typing
performSearch(value);
}, 300);
}
</script>
<input
type="text"
bind:value={query}
on:input={e => handleSearch(e.target.value)}
placeholder="Search..."
/>
<template>
<input v-model="query" @input="handleSearch" placeholder="Search..." />
</template>
<script setup>
import { ref } from 'vue';
import { useDebounce } from 'use-simple-debounce/vue';
const query = ref('');
const debounced = useDebounce();
const handleSearch = () => {
debounced(() => {
// This will be debounced - only executes 300ms after the last call
performSearch(query.value);
}, 300);
};
</script>
import { useDebounce } from 'use-simple-debounce/vanilla';
const debounced = useDebounce();
// Get the cancel function for the debounced execution
const cancel = debounced(() => {
// This will be debounced - only executes 300ms after the last call
performSearch(query);
}, 300);
// To cancel the pending execution
cancel();
import { useDebounce } from 'use-simple-debounce';
function AutoSaveEditor() {
const [content, setContent] = useState('');
const debounced = useDebounce();
const handleChange = (newContent: string) => {
setContent(newContent);
debounced(async () => {
try {
// Save after 1 second of inactivity
await saveToServer(newContent);
console.log('Auto-saved!');
} catch (err) {
console.error('Save failed:', err);
}
}, 1000);
};
return (
<textarea
value={content}
onChange={(e) => handleChange(e.target.value)}
placeholder="Start typing..."
/>
);
}
import { useDebounce } from 'use-simple-debounce';
function SearchComponent() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const debounced = useDebounce();
const performSearch = async (searchQuery: string) => {
const response = await fetch(`/api/search?q=${searchQuery}`);
const data = await response.json();
setResults(data.results);
};
const handleInputChange = (value: string) => {
setQuery(value);
debounced(() => performSearch(value), 300);
};
return (
<div>
<input
type="text"
value={query}
onChange={(e) => handleInputChange(e.target.value)}
placeholder="Search..."
/>
<ul>
{results.map((result) => (
<li key={result.id}>{result.title}</li>
))}
</ul>
</div>
);
}
useDebounce() / createDebounce()Returns a debounced executor function.
Parameters: None
Returns: A function that accepts a function to debounce and an optional delay.
Type:
function useDebounce(): (fn: () => void, delay?: number) => void;
function createDebounce(): (fn: () => void, delay?: number) => void;
Framework Usage:
import { useDebounce } from 'use-simple-debounce'import { createDebounce } from 'use-simple-debounce/solid'import { createDebounce } from 'use-simple-debounce/svelte'import { useDebounce } from 'use-simple-debounce/vue'import { useDebounce } from 'use-simple-debounce/vanilla'300msThe most frequently used delay across React applications is 300ms - it provides the best balance between responsiveness and performance for most user interactions.
| Use Case | Recommended Delay | Reason |
|---|---|---|
| Search/Autocomplete | 300ms โญ |
Most common - balances UX with API efficiency |
| Form Validation | 300-500ms |
Give users time to finish typing |
| Auto-save | 1000-2000ms |
Allow time for continuous editing |
| Window Resize | 150-250ms |
Handle rapid resize events smoothly |
| Scroll Events | 100-200ms |
Maintain smooth scrolling experience |
| API Calls | 300-600ms |
Prevent excessive server requests |
Tip: Start with 300ms for user input scenarios - it's the sweet spot used by most major applications!
MIT ยฉ juji
Contributions welcome! Please feel free to submit a Pull Request.