const [lap, setLap] = useState([]);
function start(){
if(!isStart){
starting = Date.now() - elapsed;
isStart = true;
timer = setInterval(update, 1000);
console.log("timer is activated");
}
}
function stop(){
if(isStart){
isStart = false;
clearInterval(timer);
}
}
function reset(){
isStart = false;
elapsed = 0;
document.getElementById("time").textContent = "00:00:00";
clearInterval(timer);
starting = 0;
}
}
function update(){
var curr = Date.now();
elapsed = curr - starting;
var min = Math.floor(elapsed/(1000*60));
var sec = Math.floor((elapsed/1000)%60);
var msec = Math.floor((elapsed%1000)/10);
var time = [min, sec, msec]
time = time.map((element) => pad(element));
var time_str = time[0] + ":" + time[1] + ":" + time[2];
document.getElementById("time").textContent = time_str;
console.log(time_str)
}
const lap_update = (val) => {
setLap(lap => [...lap, val]);
}
<div id="lap" onClick={() => lap_update(document.getElementById("time").textContent)}>LAP</div>
以上是秒表计圈功能的代码片段。
不幸的是,单击我的 lap_update 函数时,导致启动/停止/重置功能发生故障。
(停止功能和重置功能不起作用,启动功能是双重渲染)。
我真的无法理解为什么,以及 setLap 语句中需要进行哪些更改。
请帮忙!
尝试找出 setLap 语句导致其他函数出现故障的问题(直到调用 Lap 函数,程序运行良好)。
当您使用
lap
更新 setLap
状态时,它会导致组件重新渲染。因此,如果启动函数以某种方式与重新渲染耦合,它可能会被调用多次
为此,我们可以使用
useRef
钩子来跟踪计时器并检查秒表是否正在运行以避免重新渲染问题。这将确保状态更新不会干扰计时功能。
我对您的代码进行了这些更改,这是一个工作示例
export const Stopwatch = () => {
const [lap, setLap] = useState([]);
const [elapsed, setElapsed] = useState(0);
const [isStart, setIsStart] = useState(false);
const timerRef = useRef(null);
const startingRef = useRef(0);
const pad = (num) => (num < 10 ? '0' + num : num);
const start = () => {
if (!isStart) {
startingRef.current = Date.now() - elapsed;
setIsStart(true);
timerRef.current = setInterval(update, 1000);
console.log("timer is activated");
}
};
const stop = () => {
if (isStart) {
setIsStart(false);
clearInterval(timerRef.current);
}
};
const reset = () => {
setIsStart(false);
setElapsed(0);
document.getElementById("time").textContent = "00:00:00";
clearInterval(timerRef.current);
startingRef.current = 0;
};
const update = () => {
const curr = Date.now();
const elapsed = curr - startingRef.current;
setElapsed(elapsed);
const min = Math.floor(elapsed / (1000 * 60));
const sec = Math.floor((elapsed / 1000) % 60);
const msec = Math.floor((elapsed % 1000) / 10);
const time = [min, sec, msec].map(pad);
const time_str = `${time[0]}:${time[1]}:${time[2]}`;
document.getElementById("time").textContent = time_str;
console.log(time_str);
};
const lap_update = () => {
setLap((lap) => [...lap, document.getElementById("time").textContent]);
};
return (
<div>
<div id="time">00:00:00</div>
<div id="lap" onClick={lap_update}>LAP</div>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
<button onClick={reset}>Reset</button>
<ul>
{lap.map((lapTime, index) => (
<li key={index}>{lapTime}</li>
))}
</ul>
</div>
);
};
timerRef
跟踪间隔计时器。这将防止重新渲染引起的问题
startingRef
用于保持开始时间,即使组件重新渲染时也能进行一致的计时计算
了解更多关于
useRef
钩子这里