反应倒计时重置
React Countdown Reset
我正在尝试构建一个倒数计时器,但我遇到了一个我不明白的问题。
当我按下开始时,定时器工作正常,当我暂停它时也是如此。
问题是当我按下重置按钮时,它应该停止倒计时并将其重置为原始值(目前为 25)。
当我按下它时,倒计时停止,它转到 25,但随后又转到上一个数字。例如,如果我在 16 时按下它,它会停止,转到 25,然后在 16 或 15 时返回。
我想这与 useEffect
有关,因为 handleReset
更新了 counter
和 runnning
,但我不确定为什么。
如果有人能给我解释一下原因就好了。
这是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
的问题,您需要结合使用 clearInterval
和 useRef
。逻辑可以简化,但我想这更具可读性。
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]);
我正在尝试构建一个倒数计时器,但我遇到了一个我不明白的问题。 当我按下开始时,定时器工作正常,当我暂停它时也是如此。
问题是当我按下重置按钮时,它应该停止倒计时并将其重置为原始值(目前为 25)。
当我按下它时,倒计时停止,它转到 25,但随后又转到上一个数字。例如,如果我在 16 时按下它,它会停止,转到 25,然后在 16 或 15 时返回。
我想这与 useEffect
有关,因为 handleReset
更新了 counter
和 runnning
,但我不确定为什么。
如果有人能给我解释一下原因就好了。
这是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
的问题,您需要结合使用 clearInterval
和 useRef
。逻辑可以简化,但我想这更具可读性。
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]);