我的反应代码中有一个奇怪的行为:
在开发(严格)模式下,当间隔设置为 1000 毫秒时,以下组件在清除函数中未成功清除间隔。如果我将间隔更改为稍大的值(例如 1010 毫秒)。组件卸载时可以停止回调。我不知道为什么代码会这样。有人知道为什么它有如此奇怪的行为,我应该如何解决它?
function Timer() {
const [secondsPassed, setSecondPassed] = useState(0);
const [rows, setRow] = useState(1);
const thresold = 60;
useEffect(() => {
console.log("effect start");
function onInterval() {
setSecondPassed(prevSec => {
let currentSecond = prevSec + 1;
console.log(currentSecond);
if (currentSecond % thresold === 0) {
setRow(prevRow => prevRow + 1);
}
return currentSecond;
});
}
const intervalId = setInterval(onInterval, 1000);
console.log(`setinterval: ${intervalId}`);
return () => {
console.log(`clearInterval: ${intervalId}`);
clearInterval(intervalId);
}
}, []);
return (
<>
<div className="box-x" style={{ width: secondsPassed % thresold }}></div>
</>
);
}
但是,这个时钟组件在同一个应用程序中工作得很好。
function Clock() {
const [now, setNow] = useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => {
setNow(new Date());
}, 1000);
return () => {
clearInterval(intervalId);
}
}, []);
return (<h2 >Time now is {now.getSeconds()}</h2>);
}
如果我改为使用
setTimeout()
和 setTimeout()
,它也可以在 1000 毫秒内正常工作。
环境:
v22.3.0
18.3.1
1.93.1
127.0.6533.120 arm64
请查看依赖项数组,它现在是空的。这意味着挂钩内的代码将仅在两个事件上运行 - 组件的安装和卸载。挂钩内的代码将在挂载时运行,而该代码返回的代码将在卸载时运行。这就是clearInterval 现在只能工作一次的原因。然而,这段代码运行良好,并给出了正确的结果。
useEffect(() => {
console.log("effect start");
...
}, []);
如果您仍然想了解如何强制执行clearInterval,请参阅下面的方法之一。
步骤:
a) 请向挂钩添加依赖项。
b) onInterval 函数必须移出钩子。 然后将其设置为其依赖项。
c) 现在会发生的是,在每次渲染时,函数 onInterval 将被重新定义并产生一个新的功能对象。
d) 这将导致钩子中的依赖被识别为 改变。
e) 这将导致重新同步操作。
f) 每个重新同步操作都将从执行 返回的函数,然后继续处理钩子的处理程序。
App.js
import { useEffect, useState } from 'react';
export default function Timer() {
const [secondsPassed, setSecondPassed] = useState(0);
const [rows, setRow] = useState(1);
const thresold = 60;
function onInterval() {
setSecondPassed((prevSec) => {
let currentSecond = prevSec + 1;
console.log(currentSecond);
if (currentSecond % thresold === 0) {
setRow((prevRow) => prevRow + 1);
}
return currentSecond;
});
}
useEffect(() => {
console.log('effect start');
const intervalId = setInterval(onInterval, 1000);
console.log(`setinterval: ${intervalId}`);
return () => {
console.log(`clearInterval: ${intervalId}`);
clearInterval(intervalId);
};
}, [onInterval]);
return (
<>
<div className="box-x" style={{ width: secondsPassed % thresold }}>
seconds passed : {secondsPassed}
</div>
</>
);
}
试运行