From 22e1e48508d49a3df5ba1d55d0d87b9b75e5073c Mon Sep 17 00:00:00 2001 From: Sterling Camden Date: Mon, 16 Dec 2024 13:14:27 -1000 Subject: [PATCH] Update use-debounced-callback.ts to add a flush method to the returned callback as well as give an option to simply flush on unmount --- .../use-debounced-callback.ts | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts b/packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts index a0089afc6ee..083de0f15e6 100644 --- a/packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts +++ b/packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts @@ -1,19 +1,42 @@ -import { useCallback, useEffect, useRef } from 'react'; -import { useCallbackRef } from '../use-callback-ref/use-callback-ref'; +import { useCallback, useEffect, useRef } from "react"; +import { useCallbackRef } from "../use-callback-ref/use-callback-ref"; export function useDebouncedCallback any>( - callback: T, - delay: number + callback: T, + options: number | { delay: number; flushOnUnmount?: boolean }, ) { - const handleCallback = useCallbackRef(callback); - const debounceTimerRef = useRef(0); - useEffect(() => () => window.clearTimeout(debounceTimerRef.current), []); + const delay = typeof options === "number" ? options : options.delay; + const flushOnUnmount = + typeof options === "number" ? false : options.flushOnUnmount; + const handleCallback = useCallbackRef(callback); + const debounceTimerRef = useRef(0); - return useCallback( - (...args: Parameters) => { - window.clearTimeout(debounceTimerRef.current); - debounceTimerRef.current = window.setTimeout(() => handleCallback(...args), delay); - }, - [handleCallback, delay] - ); + const lastCallback: ((...args: Parameters) => void) & { + flush?: () => void; + } = useCallback( + (...args: Parameters) => { + window.clearTimeout(debounceTimerRef.current); + const flush = () => { + if (debounceTimerRef.current !== 0) { + debounceTimerRef.current = 0; + handleCallback(...args); + } + }; + lastCallback.flush = flush; + debounceTimerRef.current = window.setTimeout(flush, delay); + }, + [handleCallback, delay], + ); + + useEffect( + () => () => { + window.clearTimeout(debounceTimerRef.current); + if (flushOnUnmount) { + lastCallback.flush?.(); + } + }, + [lastCallback, flushOnUnmount], + ); + + return lastCallback; }