自定义挂钩SetInterval

时间:2019-12-13 21:44:49

标签: reactjs settimeout react-hooks

我正在关注Dan Abramov的这篇文章:

https://overreacted.io/making-setinterval-declarative-with-react-hooks/

在本文中,Dan制作了一个自定义的useInterval挂钩,以创建动态的setInterval。

挂钩看起来像这样:

export default function useInterval(callback, delay) {

    //this useInterval function will be called whenever the parent component renders.
    // on render, savedCallback.current gets set to whatever the callback is, if the callback 
    // has changed

  const savedCallback = useRef();
  console.log("called")

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

  /**
   * Likewise, the set interval is set off,
   * and if delay is 
  */
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => {
          console.log("clearEed!")
        clearInterval(id);
      }
    }
  }, [delay]);
}

有一个我不了解的部分,在这里:

useEffect(() => {
        function tick() {
          savedCallback.current();
        }
        if (delay !== null) {
          let id = setInterval(tick, delay);
          return () => {
              console.log("clearEed!")
            clearInterval(id);
          }
        }
      }, [delay]);

我知道,如果更改延迟,则会调用此useEffect。回调被分配为tick,然后,如果delay不为null,则将id设置为SetInterval,其中tick和delay为参数。这一切都说得通。但是接下来发生的事情对我来说很奇怪。我知道useEffect可以在组件卸载时使用return语句,但是为什么我们要清除之前设置的间隔?如果有人可以通过这个方式与我交谈,我将非常感激。

特别是,我非常想帮助您理解以下内容:

if (delay !== null) {
          let id = setInterval(tick, delay);
          return () => {
              console.log("clearEed!")
            clearInterval(id);
          }
        }

我正在这样使用它:

function TimerWithHooks() {
  let [count, setCount] = useState(0);
  let [delay, setDelay] = useState(1000);


  useInterval(() => {
    setCount(count + 1);
  }, delay)

  const handleDelayChange = evt => {
      setDelay(Number(evt.target.value))
  }

  return (
      <>
        <h1>{count}</h1>
        <input value={delay} onChange={handleDelayChange} />
      </>
  );
}

export default TimerWithHooks;

2 个答案:

答案 0 :(得分:0)

我猜想Dan会在组件卸载时清除计时器,但是我认为Beater在函数执行后才这样做。舔点东西:

useEffect(() => {
    if (delay !== null) {
      let timerId = setInterval(
          () => {
              savedCallback.current();
              clearInterval(timerId);
          }, 
          delay
      );
    }
  }, [delay]);

答案 1 :(得分:0)

  

Effects with Cleanup

     

React何时能准确清除效果?   卸载组件时,React执行清理。但是,正如我们   早先了解到,效果会在每个渲染中运行,而不仅仅是一次。 这就是为什么React还会在下次运行效果之前清除以前渲染中的效果的原因。我们将讨论为什么这有助于避免错误   以及如何选择退出此行为以防产生性能   稍后出现问题。

这意味着每次delay更改时,效果都会清除以前的效果,因此,每次我们更改延迟时,它将清除计时器,并且在卸载组件时。这样,我们可以动态调整计时器,而不必担心清除计时器。