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:
parent
173cf5e94d
commit
1a42be980c
|
|
@ -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;
|
||||
Loading…
Reference in New Issue