javascript - 番茄钟(使用 React Hooks)倒计时不开始
问题描述
试图重构这个番茄钟以使用 React Hooks。单击“开始计时器”按钮时遇到倒计时未开始的问题。我认为问题来自intervalRef。
我是否正确使用了 useRef?
https://codesandbox.io/s/k95zk32897
如果你不想去沙盒:
import React, {useState, useRef } from 'react'
export default function Pomodoro() {
const [seconds, setSeconds] = useState(0)
const [workMinutes, setWorkMinutes] = useState(25)
const [restMinutes, setRestMinutes] = useState(5)
const [start, setStart] = useState(false)
const [relax, setRelax] = useState(false)
// Control functions
const intervalRef = useRef();
function startTimer() {
if(!intervalRef.current){
intervalRef.current = setInterval(1000)
}
setStart(!start)
}
function pauseTimer() {
if(!intervalRef.current){
clearInterval(intervalRef.current)
intervalRef.current = undefined
}
}
function resetTimer() {
if(!intervalRef.current){
clearInterval(intervalRef.current)
intervalRef.current = undefined
}
setSeconds(0)
setWorkMinutes(25)
setRestMinutes(5)
setStart(false)
setRelax(false)
}
function timer() {
if(seconds === 0){
setSeconds(59)
}else{
setSeconds(seconds - 1)
}
if(relax) {
if(seconds === 0){
setRestMinutes(restMinutes - 1)
}
else if(restMinutes === 5){
setRestMinutes(4)
}else{
setRestMinutes(restMinutes)
}
}
if(restMinutes === -1) {
setRestMinutes(5)
setRelax(false)
} else {
setWorkMinutes( seconds === 0 ? workMinutes - 1 : workMinutes === 25 ? 24 : workMinutes)
if (workMinutes === -1) {
setWorkMinutes(25)
setRelax(true)
}
}
}
return (
<>
{timer}
<p>{relax ? 'Take a Break' : 'Get Busy'}</p>
<p>{relax ? restMinutes : workMinutes} : {seconds < 10 ? `0${seconds}` : seconds}</p>
<button onClick={start ? pauseTimer: startTimer}>{start ? 'Pause' : 'Start'}</button>
<button onClick={resetTimer}>Reset</button>
</>
)
}
解决方案
您忘记了回调 in setInterval
,但无论如何我宁愿这样做:
import React, { useState, useEffect } from "react";
export default function Pomodoro() {
const [seconds, setSeconds] = useState(25 * 60);
const [paused, setPaused] = useState(true);
useEffect(() => {
const int = setInterval(() => {
console.log(`${Date.now()} - paused: ${paused}`);
if (!paused) {
setSeconds(s => s - 1);
}
}, 1000);
return () => {
clearInterval(int);
};
}, [paused]);
function startTimer() {
setPaused(false);
}
function pauseTimer() {
setPaused(true);
}
function resetTimer() {
setPaused(true);
setSeconds(25 * 60);
}
return (
<>
{`${Math.floor(seconds / 60)}:${("00" + (seconds % 60)).slice(-2)}`}
<button onClick={paused ? startTimer : pauseTimer}>
{paused ? "Start" : "Pause"}
</button>
<button onClick={resetTimer}>Reset</button>
</>
);
}
沙盒:https ://codesandbox.io/s/k9j70jrjy5
你真的不需要这么多状态——它们是相互依赖的,所以你可以简化逻辑(当然你可以再做一个工作/放松功能,我不介意)。
您可以像这样处理放松计时器,只需从 10 分钟而不是 25 分钟开始:
function startRelaxTimer() {
setSeconds(10 * 60);
}
或者通过在其他状态下处理它,但是你需要做两次(只有在你关心切换时记住旧状态时才可以)。
const [relax, setRelax] = useState(false);
const [relaxSeconds, setRelaxSeconds] = useState(10 * 60);
useEffect(() => {
const int = setInterval(() => {
console.log(`${Date.now()} - paused: ${paused}`);
if (!paused) {
relax ? setRelaxSecdonds(s => s - 1) : setSeconds(s => s - 1);
}
}, 1000);
return () => {
clearInterval(int);
};
}, [paused, relax]);
推荐阅读
- java - 如何使用 RxJava 1.x 进行 takeUntil 与必须调用具有不同数据的每个页面的分页?
- r - 通过闪亮的 selectInput() 将更改应用于数据表的特定单元格
- javascript - 引导模式未正确关闭
- c# - 不能将 SetVar 与 PostAdd 或 PreAdd 挂钩 PDM Api 一起使用
- c++ - 如何部署 C++ DLL
- sql - 在新列中汇总过去 7 天的销售额
- javascript - JavaScript - 遍历对象并更改嵌套属性
- maven - 为什么 Maven 找不到 ANALYZE-DUPLICATE 函数?
- kotlin - 在 Kotlin 中创建 ByteArray
- c# - 如何将sql查询重写为linq