反应倒计时重置

React Countdown Reset

我正在尝试构建一个倒数计时器,但我遇到了一个我不明白的问题。 当我按下开始时,定时器工作正常,当我暂停它时也是如此。

问题是当我按下重置按钮时,它应该停止倒计时并将其重置为原始值(目前为 25)。

当我按下它时,倒计时停止,它转到 25,但随后又转到上一个数字。例如,如果我在 16 时按下它,它会停止,转到 25,然后在 16 或 15 时返回。

我想这与 useEffect 有关,因为 handleReset 更新了 counterrunnning,但我不确定为什么。 如果有人能给我解释一下原因就好了。

这是App.js

const App = () => {
  const [counter, setCounter] = useState(25);
  const [running, setRunning] = useState(false);

  const handlePlayPause = () => {
    running ? setRunning(false) : setRunning(true);
  };

  const handleReset = () => {
    setRunning(false);
    setCounter(25);
  };

  useEffect(() => {
    if (running) {
      counter > 0 && setTimeout(() => setCounter(counter - 1), 1000);
    }
  }, [counter, running]);

  return (
    <div className="container">
      <h1>Pomodoro Timer</h1>
      <div className="set-timer">
        <Break />
        <Session />
      </div>
      <Display counter={counter} />
      <Controller handlePlayPause={handlePlayPause} handleReset={handleReset} />
    </div>
  );
};

完整代码在这里: https://codepen.io/mugg84/pen/yLepaKm?editors=0010

感谢您的帮助!

您可以进行以下更改。问题是由于 1 秒后的计数器设置状态,此时 运行 已经设置为 false,因此当 1 秒后更新计数器时,它变为旧值。因此,我们可以将其设置为 null 并处理这种情况 explicitly.Below 代码按您描述的那样工作

const App = () => {
  const [counter, setCounter] = React.useState(25);
  const [running, setRunning] = React.useState(false);

  const handlePlayPause = () => {
    running ? setRunning(false) : setRunning(true);
  };

  const handleReset = () => {
    setRunning(null);
    setCounter(25);
  };

  React.useEffect(() => {
    if (running) {
      counter > 0 && setTimeout(() => setCounter(counter - 1), 1000);
    }
    else if(running == null){
      setCounter(25);
    }
  }, [counter, running]);

  return (
    <div className="container">
      <h1>Pomodoro Timer</h1>
      <div className="set-timer">
        <Break />
        <Session />
      </div>
      <Display counter={counter} />
      <Controller handleReset={handleReset} handlePlayPause={handlePlayPause}/>
    </div>
  );
};

我没有使用 clearTimeout,这是导致问题的原因。

我已经更新了 useEffect,它非常有效。

useEffect(() => {
    if (running && counter > 0) {
      const timer = setTimeout(() => setCounter(counter - 1), 1000);
      return () => clearTimeout(timer);
    }
  }, [counter, running]);

我可能会更改这里的一些内容。

首先,handleReset 可能不应该将 running 设置为 false,因为计数器仍然是 运行。您只需重置值。

然后,要解决我建议使用 setInterval 的问题,您需要结合使用 clearIntervaluseRef。逻辑可以简化,但我想这更具可读性。

const handleReset = () => {
    // stop on reset
    clearInterval(timer.current) 
    timer.current = undefined;
    
    setCounter(25);
  };

const timer = React.useRef(undefined);
  

React.useEffect(() => {
    if (running) {
      if (!timer.current) {
        timer.current = setInterval(() => setCounter(prevCounter => prevCounter - 1), 1000);
      } else if(counter == 0 && timer.current) {
        // stop if reached 0
        clearInterval(timer.current) 
        timer.current = undefined;
      }
    } else {
      // stop if turned off
      clearInterval(timer.current)
      timer.current = undefined;
    }
  }, [counter, running]);