How would you implement a custom useDebounce hook using useState and useEffect?

It tests effect cleanup and stale closure awareness. Use useState for the debounced value, useEffect to set a setTimeout when the input changes, and return a cleanup calling clearTimeout. Omitting cleanup leaks timers and fires stale values.
What's really being asked
This question tests your understanding of React effect lifecycles, cleanup semantics, and how to avoid stale closures when managing asynchronous timers. Interviewers want to see that you know useEffect is not just for starting side effects but also for cancelling them when dependencies change or the component unmounts.
The full answer
First, initialize a piece of state with useState to hold the debounced value, usually starting with the initial input value. Second, inside useEffect, create a timer with setTimeout that waits for the specified delay in milliseconds before calling setDebouncedValue with the latest input. Third, return a cleanup function from useEffect that calls clearTimeout using the timer ID; this cancels the previous timer whenever the input value or delay changes, preventing overlapping updates. Fourth, include both the raw value and the delay in the effect dependency array so the timer resets if either changes. Fifth, return the debounced state from the hook so components can read it directly.
The mistakes people make
A major red flag is forgetting the cleanup function entirely; without clearTimeout, every keystroke spawns a new timer and all of them fire, defeating the purpose of debounce. Another mistake is omitting the delay from the dependency array, which can lead to stale closures where a 500 ms delay feels like 200 ms because the effect captured an old variable. Some candidates also try to manage the timer with useRef to avoid re-renders, which is unnecessary for a standard debounce and adds complexity without benefit. Returning the setter instead of the value is also incorrect because the hook should encapsulate the timing logic.
What usually comes next
The interviewer might ask how you would handle a changing delay prop mid-flight, or how to add a leading-edge option so the first change fires immediately. They may also ask how to unit test the hook with React Testing Library, or how to convert it to a useMemo-based implementation if the delay is zero.
A concrete example
Imagine a search input that calls an API. The user types React quickly. Without debounce, the component sends six requests. With a 300 ms delay, the effect starts a 300 ms timer on every keystroke but cancels the previous one. Only when the user pauses for 300 ms does setDebouncedValue run, triggering a single fetch.
Interview question
What is the main consequence of omitting the clearTimeout cleanup in a useDebounce hook?
- a.The delay prop captures a stale closure, causing inconsistent wait times.
- b.The effect skips execution after the first render because the timer ID is not persisted in a ref.
- c.The debounced state resets to the initial value on every keystroke.
- d.Every keystroke starts a new timer without cancelling the old one, so multiple updates fire.Correct
Why? this is the answer
Without clearTimeout, each keystroke spawns a new timer and previous timers are not cancelled, causing multiple overlapping updates to fire. Distractor A describes a different bug caused by omitting the delay from the dependency array, not by missing cleanup.
Just read this? Test yourself on what you have been reading.
Read the original → telerik.com
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on react — each one lists the topics its interview covers.
See open roles