我正在构建Pomodoro计时器,计数器应从25分钟开始递减直到0,然后再运行5分钟递减计时器。到目前为止,计时器和中断状态应被重置以准备再次运行。
但是,我在按一下按钮运行时重置时间时遇到问题。我有一个resetTimer
函数,当前正在使用它在每个周期结束时重新初始化计时器和中断计数,但是如果在计时器或中断运行时(计数到0)单击,那么resetTimer
确实确实运行了一秒钟,但是然后计时器会像按钮触发事件之前一样继续操作。
我已经尝试过调用resetTimer
和return
,如果条件resetClicked === true
调用了该函数并短暂运行但随后使用原始计时器继续运行。
我也尝试过设置一个初始化函数,该函数在调用resetClicked === true
函数之前先检查start()
是否为resetTimer
,然后再在ojit_code中再次调用此函数,但它也不起作用。
代码
import React, { useState } from "react";
export default function App() {
const [sessionLength, setSessionLength] = useState(25);
const [breakLength, setBreakLength] = useState(5);
const [timerRunning, setTimerState] = useState(false);
const [breakRunning, setBreakState] = useState(false);
let countdown;
let minutesToSecondsSession = sessionLength * 60;
let minutestoSecondsBreak = breakLength * 60;
const clear = () => clearInterval(countdown);
const start = () => {
if (timerRunning === false) {
setTimerState(true);
console.log("timer started");
const now = Date.now();
const then = now + minutesToSecondsSession * 1000;
displayTimeLeftSession(minutesToSecondsSession);
countdown = setInterval(() => {
const secondsLeft = Math.round((then - Date.now()) / 1000);
if (secondsLeft === 0) {
clear(countdown);
console.log("timer interval cleared");
breakTimer();
}
displayTimeLeftSession(secondsLeft);
}, 1000);
}
};
// end of timer function
//
// start of break timer
function breakTimer() {
if (breakRunning === false) {
setBreakState(true);
console.log("break timer started");
const now = Date.now();
const then = now + minutestoSecondsBreak * 1000;
displayTimeLeftBreak(minutestoSecondsBreak);
countdown = setInterval(() => {
const secondsLeft = Math.round((then - Date.now()) / 1000);
if (secondsLeft === 0) {
console.log("break interval cleared");
resetTimer();
return;
}
displayTimeLeftBreak(secondsLeft);
}, 1000);
}
}
function displayTimeLeftSession(minutesToSecondsSession) {
const minutes = Math.floor(minutesToSecondsSession / 60);
const remainderSeconds = minutesToSecondsSession % 60;
setSessionLength(`${minutes}:${remainderSeconds}`);
}
function displayTimeLeftBreak(minutesToSecondsBreak) {
const minutes = Math.floor(minutesToSecondsBreak / 60);
const remainderSeconds = minutesToSecondsBreak % 60;
setBreakLength(`${minutes}:${remainderSeconds}`);
}
// end of display timer logic
function incrementSession() {
if (sessionLength <= 60) {
setSessionLength(prev => prev + 1);
}
}
function decrementSession() {
if (sessionLength > 1) {
setSessionLength(prev => prev - 1);
}
}
function incrementBreak() {
if (breakLength < 60) {
setBreakLength(prev => prev + 1);
}
}
function decrementBreak() {
if (breakLength > 1) {
setBreakLength(prev => prev - 1);
}
}
const resetTimer = () => {
clear(countdown);
setTimerState(false);
setBreakState(false);
setSessionLength(0.05);
setBreakLength(0.05);
console.log("reset");
};
代码一直到return()为止,省略了JSX以节省空间,反正只是将计时器呈现到页面上,添加嵌入时遇到问题。
https://codesandbox.io/s/fcc-pomodoro-clock-3rxfh?fontsize=14&hidenavigation=1&theme=dark
编辑:
尝试将每个倒计时定义为单独的全局范围变量,然后在需要时为每个倒数调用clearInterval,但仍然存在相同的问题。
import React, { useState, useRef } from "react";
export default function App() {
const [breakLength, setBreakLength] = useState(0.05);
const [sessionLength, setSessionLength] = useState(20);
const [timerRunning, setTimerState] = useState(false);
const [breakRunning, setBreakState] = useState(false);
let sessionCountdown;
let breakCountdown;
let minutesToSecondsSession = sessionLength * 60;
let minutestoSecondsBreak = breakLength * 60;
//const clear = () => clearInterval(countdown);
const start = () => {
if (timerRunning === false) {
setTimerState(true);
console.log("timer started");
const now = Date.now();
const then = now + minutesToSecondsSession * 1000;
displayTimeLeftSession(minutesToSecondsSession);
sessionCountdown = setInterval(() => {
const secondsLeft = Math.round((then - Date.now()) / 1000);
if (secondsLeft === 0) {
clearInterval(sessionCountdown);
console.log("timer interval cleared");
breakTimer();
}
displayTimeLeftSession(secondsLeft);
}, 1000);
}
};
// end of timer function
//
// start of break timer
function breakTimer() {
if (breakRunning === false) {
setBreakState(true);
console.log("break timer started");
const now = Date.now();
const then = now + minutestoSecondsBreak * 1000;
displayTimeLeftBreak(minutestoSecondsBreak);
breakCountdown = setInterval(() => {
const secondsLeft = Math.round((then - Date.now()) / 1000);
if (secondsLeft === 0) {
console.log("break interval cleared");
clearInterval(breakCountdown);
resetTimer();
return;
}
displayTimeLeftBreak(secondsLeft);
}, 1000);
}
}
function displayTimeLeftSession(minutesToSecondsSession) {
const minutes = Math.floor(minutesToSecondsSession / 60);
const remainderSeconds = minutesToSecondsSession % 60;
setSessionLength(`${minutes}:${remainderSeconds}`);
}
function displayTimeLeftBreak(minutesToSecondsBreak) {
const minutes = Math.floor(minutesToSecondsBreak / 60);
const remainderSeconds = minutesToSecondsBreak % 60;
setBreakLength(`${minutes}:${remainderSeconds}`);
}
// end of display timer logic
function incrementSession() {
if (sessionLength <= 60) {
setSessionLength(prev => prev + 1);
}
}
function decrementSession() {
if (sessionLength > 1) {
setSessionLength(prev => prev - 1);
}
}
function incrementBreak() {
if (breakLength < 60) {
setBreakLength(prev => prev + 1);
}
}
function decrementBreak() {
if (breakLength > 1) {
setBreakLength(prev => prev - 1);
}
}
const resetTimer = () => {
clearInterval(sessionCountdown);
clearInterval(breakCountdown);
setTimerState(false);
setBreakState(false);
setSessionLength(0.05);
setBreakLength(0.05);
console.log("reset");
};
最佳答案
TL; DR; 使用可以看到正在工作的沙箱here
详细信息:
每次执行render
时,都会创建resetTimer()
和其他函数的新闭包。如果将console.log(countdown)
放在resetTimer()
声明之前,您会看到countdown
总是 undefined
就是。
setInterval
的结果保存为状态,以便稍后在resetTimer()
中使用const [countdown, setCountdown] = useState(undefined);
但是在
setInterval
内部,您仍然可以使用闭包,这更容易const interval = setInterval(() => {
...
if (secondsLeft === 0) {
clearInterval(interval);
...
}
...
}, 1000);
setCountdown(interval) // save it to the state
关于javascript - 单击按钮时未重置为间隔运行的计数器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60738689/