每 3 秒更改一次文本 React useEffect

gos*_*d12 3 javascript reactjs react-hooks use-effect

我尝试使用 useEffect() 和 setInterval() 每 3 秒更改一次文本。现在它只更改文本一次,然后就不再更改了。我究竟做错了什么?

编辑:我正在使用库“react-spring”

  const [toggle, setToggle] = useState(false)

  useEffect(() => {
    setInterval(() => {
      switch (toggle) {
        case false: setToggle(true)
        break;
        case true: setToggle(false)
        break;
      }
    }, 3000);
  }, [])

{transitions.map(({ item, props }) => item
  ? <animated.div style={props}>Text that changes #1</animated.div>
  : <animated.div style={props}>Text that changes #2</animated.div>)}
Run Code Online (Sandbox Code Playgroud)

zhu*_*ien 6

解决方案:

useEffect(() => {
    const intervalID = setInterval(() =>  {
        setToggle((toggle) => !toggle)
    }, 3000);

    return () => clearInterval(intervalID);
}, []);
Run Code Online (Sandbox Code Playgroud)

要点:

  1. 依赖项数组[]应该为空。这样您就可以确保仅在组件的初始安装时执行此效果。您只需要一个间隔,它的创建和销毁不依赖于单个变量,而是依赖于组件本身。如果您放入toggle依赖数组,则每次变量更改时都会运行此效果,从而有效地每 3 秒产生另一个间隔。如果您确实提供了清理功能,这仍然可以工作,但它更像是一个setTimeout. 但是,在您的情况下(没有清理功能),这只会引入无限数量的间隔,这些间隔将相互竞争。
  2. 您必须提供更新程序函数而setToggle不是简单的值。这可确保您使用最新的状态进行更新,而不是闭包中的过时状态。如果您只是提供一个值,则间隔会关闭您的初始值,从而更新它。通过这种方式,您将始终将初始false值更新为true,并且这将永远重复,从而为您留下一个“常量”true值。
  3. 当您使用间隔时,您应该提供一个清理函数来useEffect清除组件卸载时的间隔。这非常重要,因为跳过这一部分会引入内存泄漏和错误,因为即使在组件从 DOM 中卸载后您仍会尝试更新该组件。