likes
comments
collection
share

useInterval

作者站长头像
站长
· 阅读数 24

是从GitHub基础上修改而来,这个GitHub上的主要代码

import { useEffect, useRef } from 'react';

type Delay = number | null;
type TimerHandler = (...args: any[]) => void;

/**
 * Provides a declarative useInterval
 *
 * @param callback - Function that will be called every `delay` ms.
 * @param delay - Number representing the delay in ms. Set to `null` to "pause" the interval.
 */

const useInterval = (callback: TimerHandler, delay: Delay) => {
  const savedCallbackRef = useRef<TimerHandler>();

  useEffect(() => {
    savedCallbackRef.current = callback;
  }, [callback]);

  useEffect(() => {
    const handler = (...args: any[]) => savedCallbackRef.current!(...args);

    if (delay !== null) {
      const intervalId = setInterval(handler, delay);
      return () => clearInterval(intervalId);
    }
  }, [delay]);
};

export default useInterval;

这个版本其实已经在大部分情况已经满足了,但是我这个是在可视化大屏编辑器中的轮播表格组件使用,当大屏拖入大量轮播表格时标签页可能会无响应于是就修改成下面这个版本

import { useEffect, useRef } from 'react'

type Delay = number | null
type TimerHandler = (...args: any[]) => void

/**
 * Provides a declarative useInterval
 * https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/
 * @param callback - Function that will be called every `delay` ms.
 * @param delay - Number representing the delay in ms. Set to `null` to "pause" the interval.
 */

const Index = (callback: TimerHandler, delay: Delay) => {
  const savedCallbackRef = useRef<TimerHandler>()

  useEffect(() => {
    savedCallbackRef.current = callback
  }, [callback])

  useEffect(() => {
    if (delay && delay > 10) {
      let timeWorker = new Worker(new URL('./worker.js', import.meta.url))
      const handler = (...args: any[]) => savedCallbackRef.current!(...args)
      timeWorker.postMessage({ action: 'start', time: delay })
      timeWorker.onmessage = handler
      return () => timeWorker.terminate()
    }
  }, [delay])
}

export default Index

worker.js:

function Fn(time = 1000) {
  setTimeout(() => {
    // eslint-disable-next-line no-restricted-globals
    self.postMessage(time)
    Fn(time)
  }, time)
}
onmessage = function (e) {
  if (e.data.action === 'start') {
    Fn(e.data.time)
  }
}

主要是把setInterval改成了worker,react使用worker的话需要一个worker-plugin