[英]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 中放入了太多东西。你的minutes
和seconds
可以直接且简单地从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.