diff options
Diffstat (limited to 'src/utils/hooks')
| -rw-r--r-- | src/utils/hooks/index.ts | 1 | ||||
| -rw-r--r-- | src/utils/hooks/use-timeout/index.ts | 1 | ||||
| -rw-r--r-- | src/utils/hooks/use-timeout/use-timeout.test.ts | 50 | ||||
| -rw-r--r-- | src/utils/hooks/use-timeout/use-timeout.ts | 29 | 
4 files changed, 81 insertions, 0 deletions
| diff --git a/src/utils/hooks/index.ts b/src/utils/hooks/index.ts index 3e8b410..f1063ce 100644 --- a/src/utils/hooks/index.ts +++ b/src/utils/hooks/index.ts @@ -26,4 +26,5 @@ export * from './use-settings';  export * from './use-state-change';  export * from './use-system-color-scheme';  export * from './use-theme'; +export * from './use-timeout';  export * from './use-toggle'; diff --git a/src/utils/hooks/use-timeout/index.ts b/src/utils/hooks/use-timeout/index.ts new file mode 100644 index 0000000..70006dc --- /dev/null +++ b/src/utils/hooks/use-timeout/index.ts @@ -0,0 +1 @@ +export * from './use-timeout'; diff --git a/src/utils/hooks/use-timeout/use-timeout.test.ts b/src/utils/hooks/use-timeout/use-timeout.test.ts new file mode 100644 index 0000000..296b320 --- /dev/null +++ b/src/utils/hooks/use-timeout/use-timeout.test.ts @@ -0,0 +1,50 @@ +import { +  afterEach, +  beforeEach, +  describe, +  expect, +  it, +  jest, +} from '@jest/globals'; +import { renderHook } from '@testing-library/react'; +import { useTimeout } from './use-timeout'; + +describe('useTimeout', () => { +  beforeEach(() => { +    jest.useFakeTimers(); +  }); + +  afterEach(() => { +    jest.runOnlyPendingTimers(); +    jest.useRealTimers(); +  }); + +  it('executes the given callback with default delay', () => { +    // When less than 1ms, setTimeout use 1. Default delay is 0ms. +    const defaultTimeoutDelay = 1; +    const callback = jest.fn(); +    renderHook(() => useTimeout(callback)); + +    expect(callback).not.toHaveBeenCalled(); + +    jest.advanceTimersByTime(defaultTimeoutDelay); + +    expect(callback).toHaveBeenCalledTimes(1); +  }); + +  it('executes the given callback with custom delay', () => { +    const customDelay = 1500; +    const callback = jest.fn(); +    renderHook(() => useTimeout(callback, customDelay)); + +    expect(callback).not.toHaveBeenCalled(); + +    jest.advanceTimersByTime(1); + +    expect(callback).not.toHaveBeenCalled(); + +    jest.advanceTimersByTime(customDelay); + +    expect(callback).toHaveBeenCalledTimes(1); +  }); +}); diff --git a/src/utils/hooks/use-timeout/use-timeout.ts b/src/utils/hooks/use-timeout/use-timeout.ts new file mode 100644 index 0000000..4d1ed47 --- /dev/null +++ b/src/utils/hooks/use-timeout/use-timeout.ts @@ -0,0 +1,29 @@ +import { type MutableRefObject, useEffect, useRef } from 'react'; + +export type UseTimeoutCallback = () => void; + +export type UseTimeoutId = string | number | NodeJS.Timeout | undefined; + +/** + * React hook to schedule the execution of a one-time callback after delay. + * + * @param {UseTimeoutCallback} callback - The callback to schedule. + * @param {number} [delay] - A delay in ms. + * @returns {MutableRefObject<UseTimeoutId>} The timeout id. + */ +export const useTimeout = ( +  callback: UseTimeoutCallback, +  delay = 0 +): MutableRefObject<UseTimeoutId> => { +  const idRef = useRef<UseTimeoutId>(undefined); + +  useEffect(() => { +    idRef.current = setTimeout(() => callback(), delay); + +    return () => { +      clearTimeout(idRef.current); +    }; +  }, [callback, delay]); + +  return idRef; +}; | 
