【问题标题】:How to use setInterval with react useEffect hook correctly?如何正确使用 setInterval 和 react useEffect 挂钩?
【发布时间】:2022-01-14 11:48:39
【问题描述】:

我尝试使用 ReactJS 创建一个简单的计时器应用程序,并在互联网上找到了以下代码。

我们传递给useEffect 的函数会随着依赖关系的变化而执行,还是会随着依赖关系的变化重新创建然后执行?

我还控制台记录了useEffect 的返回函数,它在每次渲染时运行。它仅在组件卸载时运行吗?还是每次渲染?

import { useEffect,  useState } from "react";

const App = () => {
  const [isActive, setIsActive] = React.useState(false);
  const [isPaused, setIsPaused] = React.useState(true);
  const [time, setTime] = React.useState(0);

  React.useEffect(() => {
    let interval = null;

    if (isActive && isPaused === false) {
      interval = setInterval(() => {
        setTime((time) => time + 10);
      }, 10);
    } else {
      clearInterval(interval);
    }
    return () => {
      console.log("cleanup");
      clearInterval(interval);
    };
  }, [isActive, isPaused]);

  const handleStart = () => {
    setIsActive(true);
    setIsPaused(false);
  };

  const handlePauseResume = () => {
    setIsPaused(!isPaused);
  };

  const handleReset = () => {
    setIsActive(false);
    setTime(0);
  };

  return (
    <div className="stop-watch">
      {time}
      <button onClick={handleStart}>start</button>
      <button onClick={handlePauseResume}>pause</button>
      <button onClick={handleReset}>clear</button>
    </div>
  );
};

export default App;

【问题讨论】:

    标签: javascript reactjs setinterval use-effect


    【解决方案1】:

    useEffect 挂钩内的代码将在每次更改依赖项值时运行。在您的情况下,每当 isActiveisPaused 更改状态时。

    这意味着对区间的引用将丢失,因为 interval 变量被重新定义。

    要保持稳定的引用,请使用 useRef 挂钩让引用在状态更改期间保持不变。

    const App = () => {
      const [isActive, setIsActive] = useState(false);
      const [isPaused, setIsPaused] = useState(true);
      const [time, setTime] = useState(0);
      const interval = useRef(null)
    
      useEffect(() => {
        if (isActive && !isPaused) {
          interval.current = setInterval(() => {
            setTime((time) => time + 10);
          }, 10);
        } else {
          clearInterval(interval.current);
          interval.current = null;
        }
    
        return () => {
          clearInterval(interval.current);
        };
      }, [isActive, isPaused])
    
      ...
    }
    

    【讨论】:

    • 但代码有效。我不明白它是如何清除间隔的?因为随着每个依赖项的更改,对 setinterval 的引用将丢失。我说的对吗?
    • 好吧,根据您的代码,每当卸载组件时,间隔被清除,因为interval 是内部引用的。但是,暂停间隔不应按预期工作。是的,useEffect 内部的回调函数将在每次 isActiveisPaused 在第一次渲染时被更改时调用。
    • 如果您的行为与我刚才描述的不同,请创建一个可运行的示例让我们体验您的代码。
    猜你喜欢
    • 2020-09-25
    • 1970-01-01
    • 2020-09-15
    • 1970-01-01
    • 2023-02-03
    • 2021-02-13
    • 2021-03-31
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多