使用递归settimeout启动和停止计时器
我正在尝试使用递归settimeout
启动和停止计时器,因为set> setInterval
不符合我的需求。当用户按下启动时,计时器开始计数。
1 ... 2 ... 3 ... 4..5 ... 1 ... 2 ... 3..4 ... 5 ... 1..2 ... 3..4。 ..5 ...
当用户按停止时,它应该停止此计时器循环。如果我再次按开始,更改按钮的状态(流变量),则计时器应再次执行相同的操作(1..2..3..4..5..1..1..2 ... 3。 .4 ... 5 ..)
我认为这样做的方法就是这样。
const ref = useRef(null);
useEffect(() => {
if (!stream) {
ref.current=setTimeout(repeatingFunc, 1000);
} else {
clearTimeout(ref.current);
}
}, [stream]);
function repeatingFunc() {
console.log("It's been 5 seconds. Execute the function again.");
setTimeout(repeatingFunc, 5000);
}
我在做什么错?
计时器不会停止。即使我按停止,它仍在继续! (更改流状态值!)
I am trying to start and stop a timer with a recursive setTimeout
, since setInterval
doesn't fit my need. When the user presses start, the timer starts counting.
1...2...3...4..5...1...2...3..4...5...1..2...3..4...5...
And when the user presses stop, it should stop this timer loop. If I press start again, changing the state of the button (stream variable), the timer should do the same thing again (1..2..3..4..5..1..2...3..4...5..)
I thought the way to do it would be this.
const ref = useRef(null);
useEffect(() => {
if (!stream) {
ref.current=setTimeout(repeatingFunc, 1000);
} else {
clearTimeout(ref.current);
}
}, [stream]);
function repeatingFunc() {
console.log("It's been 5 seconds. Execute the function again.");
setTimeout(repeatingFunc, 5000);
}
What am I doing wrong?
The timer doesn't stop. It keeps going even if I press stop! (changing the stream state value!)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
计时器不停止的原因是因为您仅存储初始
settimeout
调用的超时ID。当repotingFunc
被称为另一个settimeout
已注册,它具有新的超时ID。因此,当您尝试使用
clearTimeOut(ref.Current)
清除超时时,您将传递过时的超时ID。由于已经调用了先前的
settimeout
注册,因此您不再需要存储以前的ID,您可以简单地用新的ID替换。请注意,
repotingFunc
的范围是在最初调用settimeout(repotingFunc,1000)
的时间点上固定的,这意味着状态和属性之类的范围可以包含过时的值。取决于您的上下文,这可能不会成为问题。您可能还需要添加
usefect
清理功能,以清除组件下马的超时。否则,即使不再安装组件,您的循环也会继续下去。假设
流
是一个布尔值(true
/false
),以上时,只要stream> stream
的值已更改,或在组件下马上。当
流
从true
更改为false
时,将调用清理功能,并清除超时。当
流
从false
更改为 true 也调用了清理功能,但由于当前的ref,因此导致了NO-OP。当前
不再注册。然后设置新的超时。请参阅: clearTimeOut()
The reason why the timer doesn't stop is because you only store the timeout ID of the initial
setTimeout
call. WhenrepeatingFunc
is called anothersetTimeout
callback is registered, which has a new timeout ID.So when you try to clear the timeout using
clearTimeout(ref.current)
you are passing an outdated timeout ID.Since the previous
setTimeout
registration is already called, you no longer need to store the previous ID and you could simply replace it with the new one.Note that the scope of
repeatingFunc
is fixed in a point in time where you initially callsetTimeout(repeatingFunc, 1000)
, meaning that things like states and properties can contain outdated values. This might or might not become a problem depending on your context.You might also want to add a
useEffect
cleanup function that clears the timeout on component dismount. Otherwise your loop keeps going, even when the component is no longer mounted.Assuming
stream
is a boolean (true
/false
) the above will clear the current timeout whenever the value ofstream
is changed, or on component dismount.When
stream
changes fromtrue
tofalse
, the cleanup function will be called and the timeout will be cleared.When
stream
changes fromfalse
totrue
the cleanup function is also called, but results in a no-op because the currentref.current
is no longer registered. Then a new timeout is set.See: MDN -
clearTimeout()
您可以定义这样的自定义计时器:
并使用它:
您可以在任何时候和间隔内更改要执行的函数。例如:在1秒内运行起始事件,然后每5秒5次做其他事情:
You can define a custom timer like this:
And use it:
You can change the function to execute in any moment and also the interval. For example: run a start event in 1 second and then, 5 times every 5 seconds do other thing: