Debounced Search Input
Challenge 4 - Medium
Description
Create a search input component that debounces user input, only triggering the search function after the user stops typing for a set duration.
Objective
Implement debouncing logic and manage timers in React.
1. Example
Explanation
The idea here is that we are going to have an input field that we want to debounce the user input. This means that we want to wait for the user to stop typing for a set duration before we trigger the search function. This is useful when we have a search input that triggers a search function on every key press. This can be a problem when the search function is expensive and we don't want to trigger it on every key press.
Debounced:
2. Implementation
Interface
The interface for this input component is very simple, is just a function that is going to be executed when the user types in the input field and the input field is debounced. We also set the time for that debounce in 1000ms.
0
1
2
3
4
5
interface DebouncedInputPropType extends InputHTMLAttributes<HTMLInputElement>{
onDebouncedChanged: (event: ChangeEvent<HTMLInputElement>) => void;
}
const DEBOUNCE_TIME = 1000;
State
We are going to have three states in this component. The first one is theevent, which is going to store the event that is triggered when the user types in the input field. The second one is the value, which is going to store the value of the input field. The last one is the debounced value, which is going to store the value of the input field after the debounce time has passed.
0
1
2
3
const [event, setEvent] = useState<ChangeEvent<HTMLInputElement>>();
const [value, setValue] = useState<string>("");
const [debouncedValue, setDebouncedValue] = useState<string>("");
Events
We are going to have two events in this component. The first one is the useEffect, which is going to be triggered every time the value of the input field changes and it's going to reset each time the debounce timer. The second one is the handleInputChange, which is going to be triggered every time the user types in the input field and it's going to save the value and the event that is triggered.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
useEffect(() => {
const id = setTimeout(() => {
setDebouncedValue(value);
if(event)
onDebouncedChanged(event);
}, DEBOUNCE_TIME);
return (() => {
clearTimeout(id);
});
}, [value]);
const handleInputChange = (event: ChangeEvent<HTMLInputElement>): void => {
setValue(event.target.value);
setEvent(event);
};
Render
The render part of this component is very simple. We are going to have an input field that is going to trigger the handleInputChange event every time the user types in the input field. We are also going to show the value of the input field and the debounced value.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
return (
<>
<label>
Value:
<input
{...rest}
onChange={handleInputChange}
value={value}
/>
</label>
<p> Debounced: {debouncedValue} </p>
</>
);
3. Complete Code
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
'use client'
import { ChangeEvent, InputHTMLAttributes, useEffect, useState } from 'react';
interface DebouncedInputPropType extends InputHTMLAttributes<HTMLInputElement>{
onDebouncedChanged: (event: ChangeEvent<HTMLInputElement>) => void;
}
const DEBOUNCE_TIME = 1000;
const DebouncedInput: React.FC<DebouncedInputPropType> = ({onDebouncedChanged, ...rest}) => {
const [event, setEvent] = useState<ChangeEvent<HTMLInputElement>>();
const [value, setValue] = useState<string>("");
const [debouncedValue, setDebouncedValue] = useState<string>("");
useEffect(() => {
const id = setTimeout(() => {
setDebouncedValue(value);
if(event)
onDebouncedChanged(event);
}, DEBOUNCE_TIME);
return (() => {
clearTimeout(id);
});
}, [value]);
const handleInputChange = (event: ChangeEvent<HTMLInputElement>): void => {
setValue(event.target.value);
setEvent(event);
};
return (
<>
<label>
Value:
<input
{...rest}
onChange={handleInputChange}
value={value}
/>
</label>
<p> Debounced: {debouncedValue} </p>
</>
);
};
export default DebouncedInput;