0

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

4
  • Because of () => clearTimeout(delayFn); which is called whenever the useeffect is rerun due to dependency changes. This clears the pending timeout and creates a new one. Commented Jul 18, 2024 at 15:04
  • You are not understanding what debouncing does. The debounced function isn't invoked until it hasn't been triggered for the delay duration. In other words, if you keep typing letters within the delay, the callback keeps getting bounced. When you stop typing, then after the delay expires you get the one call. Commented Jul 21, 2024 at 21:32
  • @DrewReese That's not it, I know how denounce is supposed to work. However, I was not sure why above code worked because I thought components unmounted only when it is destroyed. Didn't know that it would unmount on data changes as well. Commented Jul 23, 2024 at 5:38
  • Components are "destroyed" (if that's what you want to call it) when they unmount. They certainly don't unmount when updating states, they simply just re-render. Did you mean to say that you didn't understand that the useEffect hook cleanup function runs prior to the next effect being applied and when the component unmounts? Commented Jul 23, 2024 at 5:47

1 Answer 1

0

But when I tested console.log() executed just once, Why didn't setTimeout() execute 3 times ?

Because every time one of your dependencies change (ie: searchQuery or delay), the cleanup function is first ran 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 new setTimeout() to run after 5 secs
  • searchQuery will be "ab" , clear previous timeout (so that never executes its callback now), and schedule a new setTimeout() to run after 5 secs
  • searchQuery will be "abc" , clear previous timeout (so that never executes its callback now), and schedule a new setTimeout() to run after 5 secs

Timeout completes as nothing clears it and you see the setTimeout called log.

Sign up to request clarification or add additional context in comments.

3 Comments

My understanding was that components unmounted only when the component is destroyed. I was not aware that data updates also unmounted it. Can you point me to right docs to further understand this behavior ?
@Baxu It's not being unmounted, it's just that the cleanup function (which happens to also be called on unmount), is also called when your dependencies change (see Drew's link for more details, specifically details on the setup parameter).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.