@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
116 lines (115 loc) • 3.57 kB
JavaScript
"use client";
import { useCallbackRef } from "../utils/use-callback-ref/use-callback-ref.mjs";
import { useEffect, useMemo, useRef } from "react";
//#region packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts
function useDebouncedCallback(callback, options) {
const { delay, flushOnUnmount, leading, maxWait } = typeof options === "number" ? {
delay: options,
flushOnUnmount: false,
leading: false,
maxWait: void 0
} : options;
const handleCallback = useCallbackRef(callback);
const debounceTimerRef = useRef(0);
const maxWaitTimerRef = useRef(0);
const latestArgsRef = useRef(null);
const lastCallback = useMemo(() => {
const currentCallback = Object.assign((...args) => {
window.clearTimeout(debounceTimerRef.current);
latestArgsRef.current = args;
const isFirstCall = currentCallback._isFirstCall;
currentCallback._isFirstCall = false;
function clearTimeoutAndLeadingRef() {
window.clearTimeout(debounceTimerRef.current);
window.clearTimeout(maxWaitTimerRef.current);
debounceTimerRef.current = 0;
maxWaitTimerRef.current = 0;
currentCallback._isFirstCall = true;
currentCallback._hasPendingCallback = false;
}
function startMaxWaitTimer() {
if (maxWait !== void 0 && maxWaitTimerRef.current === 0) maxWaitTimerRef.current = window.setTimeout(() => {
if (debounceTimerRef.current !== 0) {
const latestArgs = latestArgsRef.current;
clearTimeoutAndLeadingRef();
handleCallback(...latestArgs);
}
}, maxWait);
}
if (leading && isFirstCall) {
handleCallback(...args);
const resetLeadingState = () => {
clearTimeoutAndLeadingRef();
};
const flush = () => {
if (debounceTimerRef.current !== 0) {
clearTimeoutAndLeadingRef();
handleCallback(...args);
}
};
const cancel = () => {
clearTimeoutAndLeadingRef();
};
currentCallback.flush = flush;
currentCallback.cancel = cancel;
debounceTimerRef.current = window.setTimeout(resetLeadingState, delay);
startMaxWaitTimer();
return;
}
if (leading && !isFirstCall) {
currentCallback._hasPendingCallback = true;
const flush = () => {
if (debounceTimerRef.current !== 0) {
clearTimeoutAndLeadingRef();
handleCallback(...args);
}
};
const cancel = () => {
clearTimeoutAndLeadingRef();
};
currentCallback.flush = flush;
currentCallback.cancel = cancel;
const resetLeadingState = () => {
clearTimeoutAndLeadingRef();
};
debounceTimerRef.current = window.setTimeout(resetLeadingState, delay);
startMaxWaitTimer();
return;
}
currentCallback._hasPendingCallback = true;
const flush = () => {
if (debounceTimerRef.current !== 0) {
clearTimeoutAndLeadingRef();
handleCallback(...args);
}
};
const cancel = () => {
clearTimeoutAndLeadingRef();
};
currentCallback.flush = flush;
currentCallback.cancel = cancel;
debounceTimerRef.current = window.setTimeout(flush, delay);
startMaxWaitTimer();
}, {
flush: () => {},
cancel: () => {},
isPending: () => currentCallback._hasPendingCallback,
_isFirstCall: true,
_hasPendingCallback: false
});
return currentCallback;
}, [
handleCallback,
delay,
leading,
maxWait
]);
useEffect(() => () => {
if (flushOnUnmount) lastCallback.flush();
else lastCallback.cancel();
}, [lastCallback, flushOnUnmount]);
return lastCallback;
}
//#endregion
export { useDebouncedCallback };
//# sourceMappingURL=use-debounced-callback.mjs.map