繁体   English   中英

setInterval 只执行一次

[英]setInterval only executes once

我正在处理 React 组件,在表单提交时,计时器接收来自 slider 组件的值输入并开始倒计时到零。 但是,它只是在triggerClock()中的setInterval function的1之后定时器停止。 我不知道该怎么办。

我的 React 组件:

const Home = (props) => {
  let timeInMinutes;
  let timeInSeconds;

  const [time, setTime] = useState(0);
  const [minutes, setMinutes] = useState(0);
  const [seconds, setSeconds] = useState(0);

  const handleTimeChange = (event) => {
    setTime(event.target.value);
  };

  const triggerClock = () => {
    const interval = setInterval(() => {
      if (minutes === 0 && seconds === 0) {
        clearInterval(interval);
      }

      if (seconds === 0) {
        setSeconds((sec) => sec + 59);
        setMinutes((min) => min - 1);
      } else {
        setSeconds((sec) => sec - 1);
      }
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  };

  const handleFormSubmit = (event) => {
    event.preventDefault();
    timeInMinutes = time;
    timeInSeconds = timeInMinutes * 60;
    setMinutes(timeInSeconds / 60);
    setSeconds(timeInSeconds % 60);
    triggerClock();
  };

  return (
    <React.Fragment>
      <Header />
      <Container maxWidth="xs" sx={{ textAlign: "center" }}>
        <Typography variant="h5">Set Time (Minutes)</Typography>
        <Box component="form" onSubmit={handleFormSubmit}>
          <Slider
            aria-label="Timer"
            valueLabelDisplay="auto"
            step={10}
            marks
            min={0}
            max={60}
            value={time}
            onChange={handleTimeChange}
          />
          <Button type="submit">Submit</Button>
        </Box>
        <div>
          {minutes}:{seconds}
        </div>
      </Container>
    </React.Fragment>
  );
};

这里有几个问题; 首先,我建议您阅读 Dan Abramov 的优秀Making setInterval declarative博客文章,这是让您了解setInterval和 React Hooks 的棘手交集的好方法。

首先,你在 React state 中放入了太多东西。你的minutesseconds可以直接且简单地从time派生。 我们不需要 React 为我们照顾它们,它们仅在“此渲染”期间相关。 所以:

  const [time, setTime] = useState(0);

  const minutes = Math.floor(time / 60);
  const seconds = time % 60;

其次,本着丹引述的精神:

“我们可以同时描述所有时间点的过程”

我们需要知道并控制计时器是否正在倒计时:

const [timerRunning, setTimerRunning] = useState(false);

...

const triggerClock = () => {
  setTimerRunning(true);
};

请注意,这样做的另一个好处是我们现在可以让我们的 GUI 反映 state:

<Button disabled={timerRunning} type="submit">Submit</Button>

最后,我们拥有编写useEffect的所有必要部分,它将包含setInterval和所需的倒计时,在正确的时间停止清理间隔:

  useEffect(() => {
    if (timerRunning) {
      const interval = setInterval(() => {
        setTime((oldTime) => {
          const newTime = oldTime - 1;
          if (newTime === 0) {
            setTimerRunning(false);
          }
          return newTime;
        });
      }, 1000);
      return () => {
        clearInterval(interval);
      };
    }
  }, [timerRunning]);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM