The interviewer wants you to create a custom React hook that wraps the setTimeout functionality with two specific requirements:
- The timer should reset if the delay value changes
- The timer should NOT reset if only the callback function changes
This is a practical question because it tests understanding of:
- React hooks
- Closures
- Cleaning up side effects
- Performance optimization
Thought Process
-
Why use a custom hook?
- Reusability across components
- Encapsulate timeout logic
- Proper cleanup to prevent memory leaks
-
Why use useRef?
- To store the latest callback without triggering re-renders
- To avoid resetting the timer when callback changes
-
Why use useEffect?
- To handle side effects (setting/clearing timeout)
- To cleanup previous timeouts
- To respond to delay changes
Code Explanation
import { useEffect, useRef } from "react";
export default function useTimeout(callback, delay) {
// Store callback in a ref to always have latest version
const callBackRef = useRef(callback);
// Update ref when callback changes
callBackRef.current = callback;
useEffect(() => {
// Read the ref when the timer fires, so the latest callback runs
const timerId = setTimeout(() => callBackRef.current(), delay);
// Cleanup function to clear timeout
return () => clearTimeout(timerId);
}, [delay]); // Only re-run if delay changes
}Usage Example
function MyComponent() {
const [count, setCount] = useState(0);
// Example usage
useTimeout(() => {
console.log("Delayed operation");
}, 1000);
return <div>My Component</div>;
}Key Points to Remember
-
useRef Importance
useRefmaintains the reference between renders- Helps avoid unnecessary timer resets
- Stores the most recent callback
-
useEffect Dependencies
- Only
delayis in dependency array - Changes to callback won't trigger effect
- Ensures timer only resets when delay changes
- Only
-
Cleanup
- Returns cleanup function to clear timeout
- Prevents memory leaks
- Runs before component unmounts or delay changes