有没有办法在 React 中遍历计时器?

Is there a way to iterate through a timer in React?

我正在尝试使用 Hooks 创建番茄钟计时器,并且我已经使用 useState 和 useEffect 设置了基本功能。我有一个 25 分钟的倒计时计时器,每次倒数到 0 时,它都会启动一个 5 分钟的休息计时器。我现在想弄清楚的是如何创建一个迭代,说“每 4 次计时器达到 0,将休息时间从 5 分钟更改为 15 分钟,然后再回到 5 分钟。”我想以这种方式创建会话,它会说第 4 个会话,然后它会回到第 1 个。但我真的不确定在这里做什么。

  import React, { useState, useEffect } from "react";

function Pomodoro() {
  const [minutes, setMinutes] = useState(25);
  const [seconds, setSeconds] = useState(0);
  const [displayMessage, setDisplayMessage] = useState(false);
  const [session, setSession] = useState(1);

  useEffect(() => {
    let interval = setInterval(() => {
      clearInterval(interval);

      if (seconds === 0 && minutes !== 0) {
        setSeconds(59);
        setMinutes(minutes -1);
      } else if (seconds === 0 && minutes === 0) {
        let minutes = displayMessage ? 24 : 4;
        let seconds = 59;

        setSeconds(seconds);
        setMinutes(minutes);
        setDisplayMessage(!displayMessage);
      } else {
        setSeconds(seconds -1);
      }
    }, 1000);
  }, [seconds]);

  const timerMinutes = minutes < 10 ? `0${minutes}` : minutes;
  const timerSeconds = seconds < 10 ? `0${seconds}` : seconds;
  return (
    <div className="pomodoro">
        <div>Session:{session} </div>
      <div className="message">
        {displayMessage && <div>Break time! New Session starts in:</div>}
      </div>
      <div className="timer">
        {timerMinutes}:{timerSeconds}
      </div>
    </div>
  );
}

export default Pomodoro;

您使用计数器来跟踪已完成会话的方法似乎很有意义。如果你想每四次迭代使用不同的休息时间,你可以使用 remainder 运算符,如下所示:

let breakTime = (session % 4) === 0 ? 14 : 0;

然后,您只需确保每次完成会话时将 session 变量递增 1。这也意味着您只想在不“休息”时增加它,因此您必须确保防范这种情况。

使用我测试过的完整代码更新答案。请注意我所做的以下更改:

  • 我只是以秒为单位跟踪计时器 - 这降低了内部的复杂性 useEffect 并且您可以从秒转换为其他格式(再次尝试使用余数运算符)
  • 将周期长度移至常量
  • 为清楚起见,将变量 displayMessage 重命名为 isOnBreak
import React, { useState, useEffect } from "react";

// Define the period lengths (in seconds)
const workTime = 2;
const shortBreakTime = 4;
const longBreakTime = 6;

function Pomodoro() {
  const [seconds, setSeconds] = useState(workTime);
  // Renamed this variable for clarity to indicate it is a boolean
  const [isOnBreak, setIsOnBreak] = useState(false);
  const [session, setSession] = useState(1);

  useEffect(() => {
    let interval = setInterval(() => {
      clearInterval(interval);

      if (seconds === 0) {
        let breakTime = (session % 4 === 0) ? longBreakTime : shortBreakTime;
        let seconds = !isOnBreak ? breakTime : workTime;
        // A session is complete when work and break is done, 
        // so only increment when finishing a break
        if (isOnBreak) setSession(session+1);
        setSeconds(seconds);
        setIsOnBreak(!isOnBreak);
      } else {
        setSeconds(seconds -1);
      }
    }, 1000);
  }, [seconds]);

  // Here you could convert from seconds to minutes and seconds or whatever time format you prefer
  const timerSeconds = seconds < 10 ? `0${seconds}` : seconds;
  return (
    <div className="pomodoro">
        <div>Session:{session} </div>
      <div className="message">
        {isOnBreak && <div>Break time! New Session starts in:</div>}
      </div>
      <div className="timer">
        {timerSeconds}
      </div>
    </div>
  );
}