Implementing a useTimeout Hook in React
The useTimeout hook is a utility that allows you to execute a function after a specified delay, similar to setTimeout but with React's lifecycle management. This is particularly useful for tasks like debouncing, rate limiting, or triggering actions after a user interaction, ensuring clean component updates and preventing unnecessary re-renders. Your task is to implement this hook, ensuring it handles cleanup properly and integrates seamlessly with React's re-rendering cycle.
Problem Description
You need to implement a custom React hook called useTimeout that accepts two arguments:
timeout: A number representing the delay in milliseconds before the provided function is executed.callback: A function to be executed after the specified timeout.
The hook should:
- Set up a timeout using
setTimeoutwhen the component mounts or when thetimeoutorcallbackvalues change. - Clear the timeout using
clearTimeoutwhen the component unmounts or when thetimeoutorcallbackvalues change. This prevents memory leaks and unexpected behavior. - Return a boolean value indicating whether the timeout is currently active.
Key Requirements:
- The hook must be written in TypeScript.
- The timeout should be cleared before a new timeout is set if the
timeoutorcallbackvalues change. - The
callbackfunction should be called with the same arguments it was defined with. - The hook should handle edge cases gracefully, such as a
timeoutvalue of 0.
Expected Behavior:
- When the component mounts, the timeout is initiated.
- When the component unmounts, the timeout is cleared.
- If the
timeoutvalue changes, the existing timeout is cleared, and a new timeout is initiated with the new value. - If the
callbackfunction changes, the existing timeout is cleared, and a new timeout is initiated with the new callback. - The
callbackfunction is executed after the specifiedtimeouthas elapsed. - The returned boolean value accurately reflects whether a timeout is currently active.
Edge Cases to Consider:
timeoutvalue is 0: The callback should be executed immediately.callbackisnullorundefined: The hook should not attempt to execute a non-existent function.- Component unmounts before the timeout completes: The timeout should be cleared.
- Rapid changes in
timeoutorcallback: The hook should efficiently manage multiple timeouts without creating memory leaks.
Examples
Example 1:
Input: timeout = 2000, callback = () => console.log("Timeout executed!");
Output: Initially returns true, after 2000ms returns false, and logs "Timeout executed!" to the console.
Explanation: A timeout is set for 2000ms. After 2000ms, the callback is executed, and the timeout is cleared.
Example 2:
Input: timeout = 1000, callback = () => console.log("Timeout executed!");, timeout changes to 3000 after 500ms.
Output: Initially returns true, after 3000ms returns false, and logs "Timeout executed!" to the console.
Explanation: A timeout is set for 1000ms. Before it completes, the timeout value changes to 3000ms. The initial timeout is cleared, and a new timeout is set for 3000ms. After 3000ms, the callback is executed, and the timeout is cleared.
Example 3:
Input: timeout = 0, callback = () => console.log("Timeout executed!");
Output: Immediately returns false, and logs "Timeout executed!" to the console.
Explanation: A timeout with a value of 0 is set, which executes the callback immediately.
Constraints
- The
timeoutvalue must be a non-negative number. - The
callbackfunction must be a function ornull/undefined. - The hook should be performant and avoid unnecessary re-renders.
- The implementation should be concise and readable.
Notes
- Consider using
useEffectto manage the timeout lifecycle. - Pay close attention to how you clear the timeout to prevent memory leaks.
- Think about how to handle changes in the
timeoutandcallbackvalues efficiently. - The returned boolean value is a useful indicator of the timeout's state and can be used for conditional rendering or other purposes.