onClick 减少每次点击的次数而不是启动计时器

onClick decreases the number with each click rather than starting the timer

所以我正在用 React 构建一个冥想应用程序。为了简单起见,我给了它 25 分钟的倒计时。

我希望在单击按钮时开始倒计时。但是,当我将 setInterval 包装在 handleClick() 函数中时,每次点击秒数都会减少,而不是触发一次倒计时。

感谢任何帮助,提前致谢。

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


function Timer() {
  const [minutes, setMinutes] = useState(25);
  const [seconds, setSeconds] = useState(0);

  function handleClick() {
    console.log('Clicked');
    let interval = setInterval(() => {
      clearInterval(interval);
      if (seconds === 0) {
        if (minutes !== 0) {
          setSeconds(59);
          setMinutes(minutes - 1);
      } else {
        setSeconds(seconds - 1);
      }
    }, 1000)
  }

  const timerMinutes = minutes < 10 ? `0${minutes}`: minutes;
  const timerSeconds = seconds < 10 ? `0${seconds}` : seconds;

  return (
    <>
      <div className="grey-box">
        <div className="number-box">
          <h2 className="timer-text">{timerMinutes}:{timerSeconds}</h2>
        </div>
        <div className="buttons-container">
          <button className="timer-button" onClick={handleClick}>
            <img 
              className="play" 
              src="https://img.icons8.com/ios-glyphs/90/ffffff/play--v1.png" 
            />
          </button>
        </div>
      </div>
    </>
    );
  }

export default Timer;

您声明每次点击都会减去一分钟:

setMinutes(minutes - 1);

如果希望定时器只设置一次,可以查看是否设置过,如果设置过,则中止handleClick函数。计时器的 let 声明将仅在该代码块中可用(根据 运行)。因此,当发生另一次点击时,您将无法访问计时器。使用“this.interval”(函数范围)或“var interval”(global/window 范围),然后您将能够在 handleClick 函数的顶部检查是否已设置计时器。

if (this.interval) return;

OR

if (interval) return;

您正在以更复杂的方式创建计时器。我制作了一个示例,可以涵盖此用例以及一些边缘情况。

Codesandbox link

import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";
import "./styles.css";

function ClearTimer(TimerHndlRef) {
    clearInterval(TimerHndlRef.current);
    TimerHndlRef.current = null;
}
function App() {
    const TimerHndlRef = useRef();
    const [seconds, secondsSet] = useState(5);
    const onClick = () => {
        if (TimerHndlRef.current) {
            ClearTimer(TimerHndlRef);
            return;
        }
        TimerHndlRef.current = setInterval(
            () =>
                secondsSet((s) => {
                    const v = s - 1;
                    if (v > 0) return v;
                    ClearTimer(TimerHndlRef);
                    return 0;
                }),
            1000,
        );
    };
    const onChange = (e) => secondsSet(parseInt(e.target.value, 10));
    useEffect(() => {
        return () => {
            if (!TimerHndlRef.current) return;
            ClearTimer(TimerHndlRef);
        };
    }, []);
    const mLeft = Math.floor(seconds / 60);
    const sLeft = seconds - mLeft * 60;
    const mDisp = mLeft < 10 ? `0${mLeft}` : mLeft;
    const sDisp = sLeft < 10 ? `0${sLeft}` : sLeft;
    return (
        <div>
            <p>
                <input type="number" value={seconds} onChange={onChange} /> = {mDisp}m +{" "}
                {sDisp}s
            </p>
            <button onClick={onClick}>Test</button>
        </div>
    );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);