feat(32-01): create useDebounceCallback hook

- Implements ref-based debounce pattern for stable timers
- Solves stale closure problem with debounced callbacks
- useRef stores latest callback, useMemo creates debounce once
- Cleanup on unmount via useEffect return
- Exports both named and default for flexibility
This commit is contained in:
Nuwan 2026-03-05 19:35:23 +05:30
parent 173cf5e94d
commit 1a42be980c
1 changed files with 42 additions and 0 deletions

View File

@ -0,0 +1,42 @@
import { useRef, useEffect, useMemo } from 'react';
import { debounce } from 'lodash';
/**
* Hook that creates a stable debounced callback with fresh closure access.
* Solves the problem of debounce recreation when dependencies change.
*
* Pattern: useRef stores latest callback, useMemo creates debounce once.
* Source: https://www.developerway.com/posts/debouncing-in-react
*
* @param {Function} callback - The callback to debounce
* @param {number} delay - Debounce delay in ms (default: 500)
* @returns {Function} Debounced function that always uses latest callback
*/
export const useDebounceCallback = (callback, delay = 500) => {
const callbackRef = useRef(callback);
// Always keep ref current with latest callback
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
// Create debounced function once - never recreated
const debouncedFn = useMemo(
() =>
debounce((...args) => {
if (callbackRef.current) {
callbackRef.current(...args);
}
}, delay),
[delay] // Only recreate if delay changes
);
// Cleanup on unmount
useEffect(() => {
return () => debouncedFn.cancel();
}, [debouncedFn]);
return debouncedFn;
};
export default useDebounceCallback;