0
# Value Debouncing
1
2
Value debouncing with `useDebounce` delays value updates until a specified delay has passed without changes. This is perfect for optimizing React component re-renders when dealing with rapidly changing state values like user input, search queries, or form fields.
3
4
## Capabilities
5
6
### useDebounce Hook
7
8
Creates a debounced version of a value that only updates after the specified delay period.
9
10
```typescript { .api }
11
/**
12
* Debounces a value, delaying updates until after delay milliseconds have elapsed
13
* since the last time the value changed.
14
*
15
* @param value - The value to debounce
16
* @param delay - The number of milliseconds to delay
17
* @param options - Optional configuration object
18
* @returns Tuple of [debouncedValue, controlFunctions]
19
*/
20
function useDebounce<T>(
21
value: T,
22
delay: number,
23
options?: {
24
maxWait?: number;
25
leading?: boolean;
26
trailing?: boolean;
27
equalityFn?: (left: T, right: T) => boolean;
28
}
29
): [T, DebouncedState<(value: T) => void>];
30
```
31
32
**Parameters:**
33
34
- `value: T` - The value to debounce (can be any type)
35
- `delay: number` - Delay in milliseconds before updating the debounced value
36
- `options` - Optional configuration object with:
37
- `maxWait?: number` - Maximum time the value is allowed to be delayed before it's updated
38
- `leading?: boolean` - If true, updates the value immediately on first change, then debounces subsequent changes
39
- `trailing?: boolean` - If true (default), updates the value after the delay period
40
- `equalityFn?: (left: T, right: T) => boolean` - Custom equality function to determine if the value has changed (defaults to `===`)
41
42
**Returns:**
43
- `[T, DebouncedState]` - A tuple containing the debounced value and control functions (`cancel`, `flush`, `isPending`)
44
45
**Usage Examples:**
46
47
```typescript
48
import React, { useState } from 'react';
49
import { useDebounce } from 'use-debounce';
50
51
// Basic text input debouncing
52
function SearchInput() {
53
const [searchTerm, setSearchTerm] = useState('');
54
const [debouncedSearchTerm] = useDebounce(searchTerm, 500);
55
56
// This effect will only run when debouncedSearchTerm changes
57
React.useEffect(() => {
58
if (debouncedSearchTerm) {
59
// Perform API search
60
console.log('Searching for:', debouncedSearchTerm);
61
}
62
}, [debouncedSearchTerm]);
63
64
return (
65
<input
66
type="text"
67
value={searchTerm}
68
onChange={(e) => setSearchTerm(e.target.value)}
69
placeholder="Search..."
70
/>
71
);
72
}
73
74
// Leading option - immediate first update
75
function InstantSearch() {
76
const [query, setQuery] = useState('');
77
const [debouncedQuery] = useDebounce(query, 1000, { leading: true });
78
79
// First change updates immediately, subsequent changes are debounced
80
return (
81
<div>
82
<input value={query} onChange={(e) => setQuery(e.target.value)} />
83
<p>Debounced: {debouncedQuery}</p>
84
</div>
85
);
86
}
87
88
// With control functions
89
function ControlledDebounce() {
90
const [text, setText] = useState('');
91
const [debouncedText, { cancel, flush, isPending }] = useDebounce(text, 1000);
92
93
return (
94
<div>
95
<input value={text} onChange={(e) => setText(e.target.value)} />
96
<p>Text: {text}</p>
97
<p>Debounced: {debouncedText}</p>
98
<button onClick={cancel}>Cancel</button>
99
<button onClick={flush}>Flush Now</button>
100
<p>Pending: {isPending() ? 'Yes' : 'No'}</p>
101
</div>
102
);
103
}
104
105
// Custom equality function for objects
106
function ObjectDebounce() {
107
const [user, setUser] = useState({ name: '', email: '' });
108
const [debouncedUser] = useDebounce(
109
user,
110
500,
111
{
112
equalityFn: (prev, next) =>
113
prev.name === next.name && prev.email === next.email
114
}
115
);
116
117
return (
118
<div>
119
<input
120
value={user.name}
121
onChange={(e) => setUser({ ...user, name: e.target.value })}
122
placeholder="Name"
123
/>
124
<input
125
value={user.email}
126
onChange={(e) => setUser({ ...user, email: e.target.value })}
127
placeholder="Email"
128
/>
129
<p>Debounced: {JSON.stringify(debouncedUser)}</p>
130
</div>
131
);
132
}
133
134
// MaxWait option
135
function MaxWaitExample() {
136
const [value, setValue] = useState('');
137
const [debouncedValue] = useDebounce(value, 500, { maxWait: 2000 });
138
139
// Will update after 500ms of no changes, or after 2000ms maximum
140
return (
141
<div>
142
<input value={value} onChange={(e) => setValue(e.target.value)} />
143
<p>Debounced (max 2s): {debouncedValue}</p>
144
</div>
145
);
146
}
147
```
148
149
### Control Functions
150
151
The debounced state includes control functions for managing the debounce behavior:
152
153
```typescript { .api }
154
interface ControlFunctions<ReturnT> {
155
/** Cancel any pending debounced updates */
156
cancel: () => void;
157
/** Immediately execute any pending debounced updates */
158
flush: () => ReturnT | undefined;
159
/** Check if there are any pending debounced updates */
160
isPending: () => boolean;
161
}
162
```
163
164
**Control Methods:**
165
166
- `cancel()` - Cancels any pending debounced value updates
167
- `flush()` - Immediately applies any pending debounced value updates
168
- `isPending()` - Returns `true` if there's a pending debounced update, `false` otherwise
169
170
## Common Patterns
171
172
### Form Input Optimization
173
174
```typescript
175
function OptimizedForm() {
176
const [formData, setFormData] = useState({
177
username: '',
178
email: '',
179
message: ''
180
});
181
182
// Debounce the entire form object
183
const [debouncedFormData] = useDebounce(formData, 300);
184
185
// Only validate when debounced data changes
186
React.useEffect(() => {
187
validateForm(debouncedFormData);
188
}, [debouncedFormData]);
189
190
return (
191
<form>
192
<input
193
value={formData.username}
194
onChange={(e) => setFormData(prev => ({
195
...prev,
196
username: e.target.value
197
}))}
198
/>
199
{/* More form fields... */}
200
</form>
201
);
202
}
203
```
204
205
### API Request Debouncing
206
207
```typescript
208
function AutoSuggest() {
209
const [query, setQuery] = useState('');
210
const [suggestions, setSuggestions] = useState([]);
211
const [debouncedQuery] = useDebounce(query, 400);
212
213
React.useEffect(() => {
214
if (debouncedQuery.length > 2) {
215
fetch(`/api/suggestions?q=${debouncedQuery}`)
216
.then(res => res.json())
217
.then(setSuggestions);
218
} else {
219
setSuggestions([]);
220
}
221
}, [debouncedQuery]);
222
223
return (
224
<div>
225
<input
226
value={query}
227
onChange={(e) => setQuery(e.target.value)}
228
/>
229
<ul>
230
{suggestions.map(suggestion => (
231
<li key={suggestion.id}>{suggestion.text}</li>
232
))}
233
</ul>
234
</div>
235
);
236
}
237
```