如何在React中使用状态停止异步函数的执行

问题描述 投票:0回答:1

我正在运行一个异步函数,我想使用状态来停止该函数的执行。问题是 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;

有人可以向我解释一下我应该如何实现我想要实现的目标吗?

reactjs asynchronous react-hooks state
1个回答
0
投票

该函数是一个闭包,闭包内

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>

© www.soinside.com 2019 - 2024. All rights reserved.