Shadcn Hooks

useInterval

A hook that creates an interval.

Loading...

Installation

npx shadcn@latest add @hooks/use-interval
pnpm dlx shadcn@latest add @hooks/use-interval
yarn dlx shadcn@latest add @hooks/use-interval
bun x shadcn@latest add @hooks/use-interval

Copy and paste the following code into your project.

use-memoized-fn.ts
import { useMemo, useRef } from 'react'

type noop = (this: any, ...args: any[]) => any

type PickFunction<T extends noop> = (
  this: ThisParameterType<T>,
  ...args: Parameters<T>
) => ReturnType<T>

export function useMemoizedFn<T extends noop>(fn: T) {
  const fnRef = useRef<T>(fn)

  // why not write `fnRef.current = fn`?
  // https://github.com/alibaba/hooks/issues/728
  fnRef.current = useMemo<T>(() => fn, [fn])

  const memoizedFn = useRef<PickFunction<T>>(undefined)

  if (!memoizedFn.current) {
    memoizedFn.current = function (this, ...args) {
      return fnRef.current.apply(this, args)
    }
  }

  return memoizedFn.current
}

use-interval.ts
import { useCallback, useEffect, useRef } from 'react'
import { useMemoizedFn } from '@/registry/hooks/use-memoized-fn'

export function useInterval(
  fn: () => void,
  delay?: number,
  options?: { immediate?: boolean },
) {
  const fnRef = useMemoizedFn(fn)
  const timerRef = useRef<number | null>(null)

  const clear = useCallback(() => {
    if (timerRef.current) {
      clearInterval(timerRef.current)
      timerRef.current = null
    }
  }, [])

  useEffect(() => {
    if (!(typeof delay === 'number') || delay < 0) {
      return
    }

    if (options?.immediate) {
      fnRef()
    }

    timerRef.current = window.setInterval(fnRef, delay)

    return () => {
      clear()
    }
  }, [delay, options?.immediate, fnRef, clear])

  return clear
}

API

/**
 * A hook that creates an interval.
 * @param fn - The function to execute repeatedly
 * @param delay - The delay in milliseconds between each execution. Set to null to pause the interval
 * @param options - The options for the interval
 * @param options.immediate - Whether to execute the function immediately
 * @default { immediate: false } if not provided
 * @returns A function to clear the interval
 */
export function useInterval(
  fn: () => void,
  delay: number | null = null,
  options?: { immediate?: boolean },
): () => void

Credits

Last updated on