【发布时间】:2025-12-02 17:45:01
【问题描述】:
我无法让我的 react 项目实时更新“timeRemaining”状态。我知道它是异步运行的,但我不知道如何解决这个问题。该项目按其应有的方式工作,除了“timeRemaining”应在应单击后一键更新。例如,它呈现: (开始时间:25:00)点击=> (应该是:20:00,实际上是:25:00)点击=> (应该是:15:00,实际上是:20:00)......等等......我该如何处理这个延迟?
“timeRemaining”状态由“handleFocusTimeAdd/sub”和“handleBreakTimeAdd/Sub”函数更新,并由“infoComponent”显示。
以下是全部代码:
import React, { useState } from "react";
import classNames from "../utils/class-names";
import useInterval from "../utils/useInterval";
import { minutesToDuration, secondsToDuration } from "../utils/duration";
function Pomodoro() {
// Timer starts out paused
const [isTimerRunning, setIsTimerRunning] = useState(false);
const [focusDuration, setFocusDuration] = useState(1500);
const [breakDuration, setBreakDuration] = useState(300);
const [timeRemaining, setTimeRemaining] = useState(focusDuration);
const [onBreak, setOnBreak] = useState(false);
const [showInfo, setShowInfo] = useState(false);
// Update every second if timer is running
useInterval(
() => {
setTimeRemaining((timeRemaining) => timeRemaining - 1);
play();
},
isTimerRunning ? 1000 : null
);
// Handle the PLAY button
function playPause() {
setIsTimerRunning((prevState) => !prevState);
setShowInfo(true);
}
// Handle PLAY
function play() {
if (timeRemaining === 0) {
if (onBreak) {
setTimeRemaining((timeRemaining) => timeRemaining + focusDuration);
setOnBreak(false);
}
if (!onBreak) {
setTimeRemaining((timeRemaining) => timeRemaining + breakDuration);
setOnBreak(true);
}
}
}
// Handle the STOP button
const handleStopBtn = () => {
setIsTimerRunning(false);
setFocusDuration(1500);
setBreakDuration(300);
setTimeRemaining(1500);
setShowInfo(false);
};
// Handle the focus duration view SUBTRACT
const handleFocusTimeSub = (focusDuration) => {
if (focusDuration > 300) {
setFocusDuration((focusDuration) => focusDuration - 300);
} else {
setFocusDuration((focusDuration) => focusDuration);
}
setTimeRemaining(focusDuration)
return focusDuration;
};
// Handle the focus duration view ADD
const handleFocusTimeAdd = (focusDuration) => {
if (focusDuration < 3600) {
setFocusDuration((focusDuration) => focusDuration + 300);
} else {
setFocusDuration((focusDuration) => focusDuration);
}
setTimeRemaining(focusDuration)
return focusDuration;
};
// Handle the break duration view SUBTRACT
const handleBreakTimeSub = (breakDuration) => {
if (breakDuration > 60) {
setBreakDuration((breakDuration) => breakDuration - 60);
} else {
setBreakDuration((breakDuration) => breakDuration);
}
return breakDuration;
};
// Handle the break duration view ADD
const handleBreakTimeAdd = (breakDuration) => {
if (breakDuration < 900) {
setBreakDuration((breakDuration) => breakDuration + 60);
} else {
setBreakDuration((breakDuration) => breakDuration);
}
return breakDuration;
};
const infoComponent = () => {
if (showInfo) {
if (onBreak) {
return (
<div>
<div className="row mb-2">
<div className="col">
<h2 data-testid="session-title">
On Break for {secondsToDuration(breakDuration)} minutes
</h2>
<p className="lead" data-testid="session-sub-title">
{secondsToDuration(timeRemaining)} remaining
</p>
</div>
</div>
<div className="row mb-2">
<div className="col">
<div className="progress" style={{ height: "20px" }}>
<div
className="progress-bar"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0" // TODO: Increase aria-valuenow as elapsed time increases
style={{ width: "0%" }} // TODO: Increase width % as elapsed time increases
/>
</div>
</div>
</div>
</div>
);
}
if (!onBreak) {
return (
<div>
<div className="row mb-2">
<div className="col">
<h2 data-testid="session-title">
Focusing for {secondsToDuration(focusDuration)} minutes
</h2>
<p className="lead" data-testid="session-sub-title">
{secondsToDuration(timeRemaining)} remaining
</p>
</div>
</div>
<div className="row mb-2">
<div className="col">
<div className="progress" style={{ height: "20px" }}>
<div
className="progress-bar"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0" // TODO: Increase aria-valuenow as elapsed time increases
style={{ width: "0%" }} // TODO: Increase width % as elapsed time increases
/>
</div>
</div>
</div>
</div>
);
}
}
return null;
};
return (
<div className="pomodoro">
<div className="row">
<div className="col">
<div className="input-group input-group-lg mb-2">
<span className="input-group-text" data-testid="duration-focus">
Focus Duration: {secondsToDuration(focusDuration)}
</span>
<div className="input-group-append">
<button
onClick={() => handleFocusTimeSub(focusDuration)}
type="button"
className="btn btn-secondary"
data-testid="decrease-focus"
>
<span className="oi oi-minus" />
</button>
<button
onClick={() => {
handleFocusTimeAdd(focusDuration);
}}
type="button"
className="btn btn-secondary"
data-testid="increase-focus"
>
<span className="oi oi-plus" />
</button>
</div>
</div>
</div>
<div className="col">
<div className="float-right">
<div className="input-group input-group-lg mb-2">
<span className="input-group-text" data-testid="duration-break">
Break Duration: {secondsToDuration(breakDuration)}
</span>
<div className="input-group-append">
<button
onClick={() => handleBreakTimeSub(breakDuration)}
type="button"
className="btn btn-secondary"
data-testid="decrease-break"
>
<span className="oi oi-minus" />
</button>
<button
onClick={() => handleBreakTimeAdd(breakDuration)}
type="button"
className="btn btn-secondary"
data-testid="increase-break"
>
<span className="oi oi-plus" />
</button>
</div>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col">
<div
className="btn-group btn-group-lg mb-2"
role="group"
aria-label="Timer controls"
>
<button
type="button"
className="btn btn-primary"
data-testid="play-pause"
title="Start or pause timer"
onClick={playPause}
>
<span
className={classNames({
oi: true,
"oi-media-play": !isTimerRunning,
"oi-media-pause": isTimerRunning,
})}
/>
</button>
<button
onClick={handleStopBtn}
type="button"
className="btn btn-secondary"
title="Stop the session"
>
<span className="oi oi-media-stop" />
</button>
</div>
</div>
</div>
<div>{infoComponent()}</div>
</div>
);
}
export default Pomodoro;
感谢您的帮助!我是 React 新手,仍在解决问题。
【问题讨论】:
标签: javascript reactjs asynchronous onclick use-state