All files / react useInterval.ts

0% Statements 0/23
0% Branches 0/10
0% Functions 0/6
0% Lines 0/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61                                                                                                                         
import { useCallback, useEffect, useRef, useState } from 'react'
import { useLatest } from 'react-use'
 
export type UseIntervalResult<TResult> = [
  TResult | undefined,
  {
    start: (delay?: number, duration?: number) => void
    stop: () => void
  },
]
 
/**
 * 以一定的间隔时间重复调用某函数,并返回调用结果。
 *
 * @param callback 回调函数
 * @param delay 间隔时间(毫秒),非数字时将不调用或停止调用函数
 * @param duration 持续时间(毫秒)
 * @returns 返回调用结果
 */
export function useInterval<TResult>(
  callback: () => TResult,
  delay: any,
  duration?: number,
): UseIntervalResult<TResult> {
  const [result, setResult] = useState<TResult>()
  const latestCallback = useLatest(callback)
  const latestDelay = useLatest(delay)
  const latestDuration = useLatest(duration)
  const interval = useRef<any>()
 
  const stop = useCallback(() => {
    if (interval.current) {
      clearInterval(interval.current)
    }
  }, [])
 
  const start = useCallback((delay?: number, duration?: number) => {
    stop()
    delay = delay ?? latestDelay.current
    duration = duration ?? latestDuration.current
    if (typeof delay === 'number') {
      setResult(latestCallback.current())
      interval.current = setInterval(() => {
        setResult(latestCallback.current())
      }, delay)
    }
    if (typeof duration === 'number') {
      setTimeout(() => {
        stop()
      }, duration)
    }
  }, [])
 
  useEffect(() => {
    start()
    return stop
  }, [delay])
 
  return [result, { start, stop }]
}