当前位置: 首页 > 知识库问答 >
问题:

自定义挂钩SetInterval

吴胜
2023-03-14

我在关注丹·阿布拉莫夫的这篇文章:

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,然后如果延迟不为null,则id被设置为SetInterval,tick和延迟作为参数。这一切都是有道理的。但是接下来发生的事情对我来说很奇怪。我知道当组件卸载时,useffect可以接受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个答案

廖弘伟
2023-03-14

我猜Dan会在组件卸载时清除计时器,但我认为beater会在函数执行后执行此操作。有些东西可以舔这个:

useEffect(() => {
    if (delay !== null) {
      let timerId = setInterval(
          () => {
              savedCallback.current();
              clearInterval(timerId);
          }, 
          delay
      );
    }
  }, [delay]);
胡和煦
2023-03-14

效果与清理

反应到底什么时候清理效果?React在组件卸载时执行清理。然而,正如我们之前了解到的,效果对每个渲染都运行,而不仅仅是一次。这就是为什么React在下次运行效果之前还会清除上一次渲染的效果。我们将在下面讨论为什么这有助于避免错误,以及如何选择退出这种行为,以防它在后面造成性能问题。

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

 类似资料:
  • 我正试图将一个值从一个定制钩子(为服务器获取数据)保存到带有useState的功能组件状态,因为我以后需要更改这个值,更改后需要重新加载。因此,理想的行为是: 将状态变量设置为自定义挂钩中的值 我尝试的是: > 设置useState的初始值到我的钩子:

  • 所以我正在构建一个反应应用程序,我试图通过使用axios的自定义钩子简化调用我的后端api。这个钩子保持加载和错误状态,这样我就不必在发出请求的每个组件中保持该状态。它还公开了一个调用Api()函数,该函数发出实际请求,然后更改钩子中的状态。这是自定义钩子的代码。 然后,我尝试在我想要发出请求的组件中的useEffect钩子中使用这个callApi()方法。 这是预期的工作,但我的linter(设

  • 问题内容: 我想从Java中的“ AbstractBase_step”类扩展。所以我想有一个像这样的钩子: 每个步骤文件都会被调用: 当我这样做时,我得到 cuming.runtime.CucumberException:不允许扩展定义“步骤定义”或“挂钩”的类。Hello_Steps类扩展了AbstractBase_Steps类 有人为此有把戏吗? 编辑:为了重用相同的步骤定义,我创建了一个新的

  • 为了避免在这些情况下中断工作线程,可以向JVM运行时插入一个shutdown钩子,该钩子在JVM关闭启动后正确地停止LoggerContext 我想知道如何在Spring Boot应用程序中停止AsyncAppender。在Spring引导的哪个位置,我应该定义关机钩?

  • 和其它版本控制系统一样,Git 能在特定的重要动作发生时触发自定义脚本。 有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。 安装一个钩子 钩子都被存储在 Git 目录下的 hooks 子目录中。 也即绝大部分项目中的 .git/hooks 。 当你用 git init 初始

  • 据我所知,useState钩子的更新函数应该在批处理中运行,而不是在每次调用组件时重新呈现它。我创建了以下自定义挂钩: 但当我多次使用它时,每次发射都会导致重新渲染: 有没有办法优化这个?我是不是误解了什么?