reactjs - SetInterval 在 React 功能组件中不起作用
问题描述
您能否向我解释一下我的 Timer 组件出了什么问题以及如何解决?
停止和重置按钮没有按我的计划工作。
停止按钮必须停止计时器(这意味着status=false
),但保存最后一个runningTime
值。
重置按钮必须清除两个值 ( status=false, runningTime=0
) 但它只清除时间戳的列表,status
并且runningTime
保持不变。
我想我使用setInterval
函数的方式有问题,但我无法弄清楚到底是什么。
import React, { useEffect, useState, useRef } from "react";
const initialState = {
status: false,
runningTime: 0,
timestamps: []
};
export const Timer = () => {
const [watchData, setWatchData] = useState(initialState);
let timer = useRef();
useEffect(() => {
return () => {
clearInterval(timer);
};
}, [timer]);
const getUnits = (time) => {
const seconds = time / 1000;
const min = Math.floor(seconds / 60).toString();
const sec = Math.floor(seconds % 60).toString();
const msec = (seconds % 1).toFixed(3).substring(2);
return `${min}:${sec}:${msec}`;
};
const handleClick = () => {
const { status } = watchData;
if (!status) {
const startTime = Date.now() - watchData.runningTime;
timer = setInterval(() => {
setWatchData((prevState) => ({
...prevState,
status: true,
runningTime: Date.now() - startTime
}));
});
} else {
clearInterval(timer.current);
setWatchData((prevState) => ({ ...prevState, status: false }));
}
};
const handleReset = () => {
clearInterval(timer.current);
setWatchData({ ...initialState });
};
const handleLap = () => {
const timestamp = getUnits(watchData.runningTime);
console.log(timestamp);
setWatchData((prevState) => ({
...prevState,
timestamps: [...watchData.timestamps, timestamp]
}));
};
return (
<>
<p>{getUnits(watchData.runningTime)}</p>
<button onClick={handleClick}>
{watchData.status ? "Stop" : "Start"}
</button>
<button onClick={handleReset}>Reset</button>
<button onClick={handleLap}>Lap</button>
{watchData.timestamps.length > 0 && (
<ul>
{watchData.timestamps.map((t, index) => (
<li key={index}>{t}</li>
))}
</ul>
)}
</>
);
};
解决方案
您不应该重新影响timer
变量,但是您可以更新属性timer.current
,这是对您的代码的更正:
const handleClick = () => {
const { status } = watchData;
clearInterval(timer.current);
if (!status) {
const startTime = Date.now() - watchData.runningTime;
timer.current = setInterval(() => {
setWatchData((prevState) => ({
...prevState,
status: true,
runningTime: Date.now() - startTime
}));
});
} else {
setWatchData((prevState) => ({ ...prevState, status: false }));
}
}
您也可以像这样更新效果(以清除组件卸载时的间隔):
useEffect(() => {
return () => clearInterval(timer.current);
}, []);
推荐阅读
- google-bigquery - 在 ON 中使用 CASE 语句进行 LEFT JOIN 时出现 BigQuery 错误
- angular - 使用 AngularFirestore 时如何处理大数据?
- python - 虽然我可以看到 pip3 安装顺利,但无法安装 python 插件
- android - 如何在设备而不是主机上进行简单的单元测试
- get - 如何使用标记动画获取 lat 和 lgn 的值
- python - 有两个轮廓 cv2.findContour 只找到一个
- python - 循环以移动 DataFrame Datetime 中列的时间线
- windows - 如何使用 .exe 文件在命令提示符下运行命令
- html - 使用 HTML 属性作为 CSS 选择器
- python - 根据用户名确定两个状态之间的时间差