shelving
Version:
Toolkit for using data in JavaScript.
43 lines (42 loc) • 1.68 kB
JavaScript
import { useEffect, useRef, useState } from "react";
/**
* Set a state using a "debounce" delay — this ensures that the state is only updated after the specified delay has passed since the last update.
* - Useful for input fields where you want to wait until the user has stopped typing before performing an action (e.g., API call).
*/
export function useDebouncedState(initial, delay = 500) {
const [state, setState] = useState(initial);
const _internal = (useRef(undefined).current ??= {
timeout: null,
setDebouncedState(v) {
if (_internal.timeout)
clearTimeout(_internal.timeout);
_internal.timeout = setTimeout(() => setState(v), delay);
},
});
return [state, _internal.setDebouncedState];
}
/**
* Debounce a callback function — the callback will only be invoked after the specified delay has passed since the last call.
* - Useful for triggering form submissions after the user has stopped typing.
* - Automatically cleans up pending timeouts on unmount.
*/
export function useDebouncedCallback(callback, delay = 500) {
const timeoutRef = useRef(null);
const callbackRef = useRef(callback);
// Keep callback ref up to date
callbackRef.current = callback;
// Cleanup on unmount
useEffect(() => {
return () => {
if (timeoutRef.current)
clearTimeout(timeoutRef.current);
};
}, []);
return () => {
if (timeoutRef.current)
clearTimeout(timeoutRef.current);
if (callbackRef.current) {
timeoutRef.current = setTimeout(() => callbackRef.current?.(), delay);
}
};
}