I found this code from this answer https://stackoverflow.com/a/68780417/26420821
How does it work?
export function useSearchDebounce(delay = 350) {
const [search, setSearch] = useState(null);
const [searchQuery, setSearchQuery] = useState(null);
useEffect(() => {
const delayFn = setTimeout(() => {
console.log("setTimeout called");
setSearch(searchQuery);
}, delay);
return () => clearTimeout(delayFn);
}, [searchQuery, delay]);
return [search, setSearchQuery];
}
Usage :
const [search, setSearch] = useSearchDebounce();
<input onChange={(e) => setSearch(e.target.value)}/>
If we assume user types "abc" together in the input field with delay set to 5000,
At first, searchQuery
will be "a"
, it will setTimeout()
to run after 5 secs,
Then searchQuery
will be "ab"
, it will again setTimeout()
to run after 5 secs,
Then searchQuery
will be "abc"
, it will again setTimeout(
) to run after 5 secs
But when I tested console.log()
executed just once, Why didn’t setTimeout()
execute 3 times ?
Am I misunderstanding something ?
I don’t understand the code
2
Answers
Because every time one of your dependencies change (ie:
searchQuery
ordelay
), the cleanup function is first run clearing the previous timeout that had been scheduled, then it runs your useEffect callback to schedule a new timeout.So the behaviour you’re missing is that the previous timeout is cleared when the user types
"abc"
:searchQuery
will be"a"
, clear previous timeout (if one exists, one technically gets scheduled onmount), and schedule a newsetTimeout()
to run after 5 secssearchQuery
will be"ab"
, clear previous timeout (so that never executes its callback now), and schedule a newsetTimeout()
to run after 5 secssearchQuery
will be"abc"
, clear previous timeout (so that never executes its callback now), and schedule a newsetTimeout()
to run after 5 secsTimeout completes as nothing clears it and you see the
setTimeout called
log.By separating the input element state and the debounced value you get access to both: