Implement useTimeout React Hook
Create a custom React hook called useTimeout that allows developers to easily manage timeouts within their React components. This hook should provide a clear and reusable way to set a timeout that executes a callback function after a specified delay.
Problem Description
Your task is to implement a custom React hook named useTimeout in TypeScript. This hook will be responsible for managing JavaScript's setTimeout functionality within a React functional component. The hook should accept a callback function and a delay in milliseconds as arguments. It should also provide a way to clear the timeout.
Key Requirements:
- Accept Callback and Delay: The hook must accept a callback function (which takes no arguments) and a delay in milliseconds.
- Execute Callback: The provided callback function should be executed exactly once after the specified delay has elapsed.
- Clear Timeout: The hook should return a function that allows the caller to clear the timeout before it executes. This is crucial for preventing memory leaks and unexpected behavior when a component unmounts or the timeout is no longer needed.
- Handle Re-renders and Unmounting: The hook should gracefully handle component re-renders and ensure that timeouts are cleared when the component unmounts to avoid errors.
- Type Safety: Implement the hook using TypeScript for strong typing.
Expected Behavior:
When the useTimeout hook is called, it should set a timer. If the timer is not cleared using the returned clearTimeout function, the provided callback will be executed after the specified delay.
Examples
Example 1:
import React, { useState } from 'react';
import { useTimeout } from './useTimeout'; // Assuming useTimeout is in this file
function CounterComponent() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
// Set a timeout to update the message after 2 seconds
useTimeout(() => {
setMessage('Timeout finished!');
}, 2000);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<p>{message}</p>
</div>
);
}
Output (after 2 seconds):
The message state will update to "Timeout finished!".
Explanation:
The useTimeout hook is called with a callback that sets the message state. After 2000 milliseconds, this callback executes, updating the UI.
Example 2:
import React, { useState } from 'react';
import { useTimeout } from './useTimeout';
function DebounceInput() {
const [inputValue, setInputValue] = useState('');
const [debouncedValue, setDebouncedValue] = useState('');
// Use useTimeout to debounce the input value update
// The callback will only execute if the input doesn't change for 500ms
const { resetTimeout } = useTimeout(() => {
setDebouncedValue(inputValue);
}, 500);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
// Reset the timeout every time the input changes
resetTimeout();
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} placeholder="Type here..." />
<p>Debounced Value: {debouncedValue}</p>
</div>
);
}
Output:
As the user types, debouncedValue will only update 500ms after the user stops typing.
Explanation:
Each time handleChange is called, resetTimeout() is invoked, which effectively cancels the previous timeout and starts a new one. This ensures setDebouncedValue is only called after a period of inactivity.
Constraints
- The
delayparameter will be a non-negative number. - The
callbackparameter will be a function. - The hook should not introduce any performance bottlenecks.
- The hook must be implemented as a functional hook, starting with
use.
Notes
- Consider using
useRefto store the timeout ID. - Remember to clean up the timeout in the cleanup function of
useEffectto prevent memory leaks. - The callback function should ideally be stable, meaning it doesn't change on every render if its dependencies haven't changed. However, for this challenge, focus on correct timeout management.
- Think about how
setTimeoutandclearTimeoutwork in JavaScript and how they integrate with the React component lifecycle.