diff --git a/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.test.ts b/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.test.ts index b2f9ee97..c4ac2f7c 100644 --- a/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.test.ts +++ b/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.test.ts @@ -85,6 +85,30 @@ describe('useDebounceCallback()', () => { expect(debouncedCallback).not.toHaveBeenCalled() }) + it('should cancel the debounced callback on unmount', () => { + const delay = 500 + const debouncedCallback = vitest.fn() + const { result, unmount } = renderHook(() => + useDebounceCallback(debouncedCallback, delay), + ) + + act(() => { + result.current('argument') + }) + + // The callback should not be invoked immediately + expect(debouncedCallback).not.toHaveBeenCalled() + + // Unmount the component + unmount() + + // Fast forward time past the debounce delay + vitest.advanceTimersByTime(delay + 100) + + // The callback should not be invoked after unmount + expect(debouncedCallback).not.toHaveBeenCalled() + }) + it('should flush the debounced callback', () => { const delay = 500 const debouncedCallback = vitest.fn() diff --git a/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.ts b/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.ts index 94f9065a..6fb97a7d 100644 --- a/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.ts +++ b/packages/usehooks-ts/src/useDebounceCallback/useDebounceCallback.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef } from 'react' +import { useMemo, useRef } from 'react' import debounce from 'lodash.debounce' @@ -87,6 +87,8 @@ export function useDebounceCallback ReturnType>( const debounced = useMemo(() => { const debouncedFuncInstance = debounce(func, delay, options) + debouncedFunc.current = debouncedFuncInstance + const wrappedFunc: DebouncedState = (...args: Parameters) => { return debouncedFuncInstance(...args) } @@ -106,10 +108,5 @@ export function useDebounceCallback ReturnType>( return wrappedFunc }, [func, delay, options]) - // Update the debounced function ref whenever func, wait, or options change - useEffect(() => { - debouncedFunc.current = debounce(func, delay, options) - }, [func, delay, options]) - return debounced }