我正在运行一个异步函数,我想使用状态来停止该函数的执行。问题是 isRunning 变量没有在函数内部更新。
这是我的简化代码:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const runAsyncTask = async isRunning => {
while (isRunning) {
await delay(1000);
console.log("running...");
}
}
const App = () => {
const [isRunning, setIsRunning] = useState(true);
runAsyncTask(isRunning)
return (
<button
onClick={() => {
setIsRunning(false);
}}>
STOP
</button>
);
}
export default App;
有人可以向我解释一下我应该如何实现我想要实现的目标吗?
该函数是一个闭包,闭包内
isRunning
的值始终为true
。当您在渲染时再次调用该函数时,原始闭包不会受到影响,并且您将创建一个立即开始并结束的新循环,因为 isRunning
的值为 false
。
在
useEffect
块内运行循环,因此渲染不会创建新循环,并使用引用将 isRunning
的值传递到闭包中。引用是一个指向可以从外部控制的值 (current
) 的对象。
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<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>
<script type="text/babel">
const { useState, useRef, useEffect } = React;
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const runAsyncTask = async isRunningRef => {
while (isRunningRef.current) {
await delay(1000);
console.log("running...");
}
}
const App = () => {
const [isRunning, setIsRunning] = useState(true);
const isRunningRef = useRef(isRunning);
useEffect(() => {
isRunningRef.current = isRunning;
});
useEffect(() => {
runAsyncTask(isRunningRef)
}, []);
return (
<button
onClick={() => {
setIsRunning(false);
}}>
STOP
</button>
);
}
ReactDOM
.createRoot(root)
.render(<App />);
</script>