【问题标题】:How can I start / stop setInterval?如何启动/停止 setInterval?
【发布时间】:2022-12-11 00:55:41
【问题描述】:
我尝试了不同的方法,但它不起作用。
[...]
const [automatic, setAutomatic] = useState(false);
[...]
var startAuto;
useEffect(() => {
if (!automatic) {
console.log("stop");
clearInterval(startAuto);
} else {
startAuto = setInterval(() => {
changeQuestion("+");
}, 5 * 1000);
}
}, [automatic]);
[...]
<Button
onPress={() => setAutomatic(!automatic)}
title="turn on/off"
/>
[...]
当我将 setTimeout 放在 useEffect 之外时它会起作用,这样:
setTimeout(() => { clearInterval(startAuto); alert('stop'); }, 10000);
但我想要一个按钮来启动/停止
【问题讨论】:
标签:
javascript
react-native
react-hooks
setinterval
【解决方案1】:
您的 var startAuto; 在每次渲染时都会重新声明,并且由于更改状态会导致重新渲染,因此它永远不会保留对永远不会被清除的间隔的引用。
使用useEffect清理功能清除间隔。每当automatic发生变化时,它就会调用cleanup(如果之前的调用返回),如果automatic是true,它就会创建一个新的间隔循环,并返回一个新的当前间隔的清理函数。
useEffect(() => {
if(!automatic) return;
const startAuto = setInterval(() => {
changeQuestion("+");
}, 5 * 1000);
return () => {
clearInterval(startAuto);
};
}, [automatic]);
工作示例:
const { useState, useEffect } = React;
const Demo = () => {
const [automatic, setAutomatic] = useState(false);
const [question, changeQuestion] = useState(0);
useEffect(() => {
if(!automatic) return;
const startAuto = setInterval(() => {
changeQuestion(q => q + 1);
}, 5 * 100);
return () => {
clearInterval(startAuto);
};
}, [automatic]);
return (
<div>
<button
onClick={() => setAutomatic(!automatic)}
>
turn {automatic ? 'off' : 'on'}
</button>
<p>{question}</p>
</div>
);
}
ReactDOM
.createRoot(root)
.render(<Demo />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
【解决方案2】:
例如,您可以检查并使用这个钩子:
https://usehooks-ts.com/react-hook/use-interval
export default function Component() {
// The counter
const [count, setCount] = useState<number>(0)
// Dynamic delay
const [delay, setDelay] = useState<number>(1000)
// ON/OFF
const [isPlaying, setPlaying] = useState<boolean>(false)
useInterval(
() => {
// Your custom logic here
setCount(count + 1)
},
// Delay in milliseconds or null to stop it
isPlaying ? delay : null,
)
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setDelay(Number(event.target.value))
}
return (
<>
<h1>{count}</h1>
<button onClick={() => setPlaying(!isPlaying)}>
{isPlaying ? 'pause' : 'play'}
</button>
<p>
<label htmlFor="delay">Delay: </label>
<input
type="number"
name="delay"
onChange={handleChange}
value={delay}
/>
</p>
</>
)
}