Create a useDebounceCallback Hook in React
The useDebounceCallback hook is a utility that allows you to debounce a callback function within a React component. Debouncing ensures that a function is only executed after a certain amount of time has passed without any further calls to the function, preventing excessive or rapid execution. This is particularly useful for handling events like input changes, window resizing, or scroll events where you want to avoid triggering updates too frequently.
Problem Description
You are tasked with creating a custom React hook called useDebounceCallback. This hook should accept a callback function and a delay (in milliseconds) as arguments. It should return a debounced version of the callback function. The debounced function should only be executed after the specified delay has elapsed without any further calls to the debounced function.
Key Requirements:
- Debouncing Logic: The core functionality should debounce the provided callback.
- Delay Parameter: The hook must accept a
delayparameter to control the debounce time. - Return Value: The hook should return a debounced function that can be used like a regular function.
- Cleanup: The hook should properly clean up any timers created when the component unmounts to prevent memory leaks.
- TypeScript: The solution must be written in TypeScript.
Expected Behavior:
- When the component mounts, the hook should initialize a timer.
- Each time the debounced function is called, the timer should be reset.
- If the timer reaches the specified
delaywithout being reset, the original callback function should be executed. - When the component unmounts, the timer should be cleared to prevent memory leaks.
Edge Cases to Consider:
- Zero Delay: What should happen if the delay is set to 0? (Consider whether it should execute immediately or not execute at all). For this challenge, a delay of 0 should execute the callback immediately.
- Rapid Calls: The callback should only be executed once after a series of rapid calls within the debounce window.
- Component Unmount: The timer should be cleared if the component unmounts before the debounce delay has elapsed.
- Callback with Arguments: The debounced function should correctly pass any arguments provided to it to the original callback function.
Examples
Example 1:
Input:
callback: () => console.log("Debounced function executed!");
delay: 500
Calls: debouncedFunction(), debouncedFunction(), debouncedFunction() (all within 200ms)
Output:
"Debounced function executed!" (printed after 500ms from the *last* call)
Explanation:
The first call starts a timer. The subsequent calls reset the timer. After 500ms from the last call, the callback is executed.
Example 2:
Input:
callback: (message: string) => console.log("Message:", message);
delay: 300
Calls: debouncedFunction("Hello"), debouncedFunction("World"), debouncedFunction("!") (all within 100ms)
Output:
"Message: !" (printed after 300ms from the *last* call)
Explanation:
The callback receives the last argument passed to the debounced function ("!").
Example 3: (Edge Case - Component Unmount)
Input:
callback: () => console.log("This should not be printed");
delay: 1000
Scenario: Component unmounts after 500ms of the first call to debouncedFunction.
Output:
(Nothing is printed to the console)
Explanation:
The timer is cleared during unmount, preventing the callback from being executed.
Constraints
- The
delayparameter must be a non-negative number. - The callback function must be a function.
- The hook should be performant and avoid unnecessary re-renders.
- The hook should be compatible with functional React components.
Notes
- Consider using
setTimeoutandclearTimeoutfor the debouncing logic. - The
useEffecthook is essential for managing the timer and cleanup. - Think about how to properly handle the arguments passed to the debounced function.
- Ensure your code is well-typed and handles potential errors gracefully.
- The hook should return a function, not an object containing the function. This simplifies usage.