【问题标题】:How to stop for loop in React till asynchronous action is done?如何在 React 中停止 for 循环直到异步操作完成?
【发布时间】:2019-12-15 11:41:55
【问题描述】:

我有一个组件,在它内部我正在与 API 通信(这里我设置了超时来代替模拟)。我在 for 循环中进行了一些调用,以更新当前交互索引上的数组。最后我想 console.log 所有带有添加数据的数组。这就是问题所在。循环正在经历所有迭代,并且不会等待完成异步任务,因此它正在打印带有注释的空数组,说明有数据但刚刚到来。

我尝试添加 useState 但没有解决问题。

import React, {useEffect} from 'react';

function Ingredients() {
    const heatingStepsTime = [];
    const heatingStepsTimer = [];

    function getTimes(i, type) {
        if (type === "time") {
            setTimeout(() => {
                heatingStepsTime[i] = i;
            }, 1000);
        } else {
            setTimeout(() => {
                heatingStepsTimer[i] = i + 1;
            }, 1000)
        }
    }

    const getProcess = () => {
        for (let i = 0; i < 3; i++) {
            getTimes(i, "time");
            getTimes(i, "timer");
        }
    };

    useEffect(getProcess, []);
    console.log(heatingStepsTime);
    console.log(heatingStepsTimer);

    return (
        <div className="App">
            test
        </div>
    );
}

export default Ingredients;

有没有办法在 React 中停止 for 循环迭代,以便在异步任务完成时继续循环?

【问题讨论】:

  • @giorgimoniava 但是如何在 for 循环中使用它?
  • 你在使用promise吗?还是异步/等待?

标签: javascript reactjs react-hooks


【解决方案1】:

试试这个

function App() {
    function getTimes(i) {
      return new Promise(resolve => {
        setTimeout(() => {
            resolve(i);
        }, 1000);
      });
    }

    const [heatingStepsTime, setHeatingStepsTime] = useState([]);

    const getProcess = () => {
      const promises = '0'.repeat(10).split('').map((c, i)=>getTimes(i));
      Promise.all(promises)
      .then(result=> setHeatingStepsTime(result));
    };

    useEffect(getProcess, []);

    return (
        <div className="App">
          {heatingStepsTime.map((p,i)=><div key={i}>{p}</div>)}
        </div>
    );
}

https://stackblitz.com/edit/react-szrhwk

解释:

function getTimes(i) {
      return new Promise(resolve => {
        setTimeout(() => {
            resolve(i);
        }, 1000);
      });
    }

要模拟 API,您应该使用 Promise 模拟它。此计时器将在超时时解决承诺。

const [heatingStepsTime, setHeatingStepsTime] = useState([]);

您希望将结果存储到一个状态中,以便 react 知道渲染结果

'0'.repeat(10).split('')

这只是为了模拟您的 for 循环...如果您有多个 API 调用,您可以忽略它...只需将其替换为

const promises = [apiCall1(), apiCall2()];
Promise.all(promises)
      .then(result=> setHeatingStepsTime(result));

这将等待所有的 Promise 解决并将结果存储到状态中

【讨论】:

    【解决方案2】:

    我找到了解决方案。在 React 中,我们需要使用 useState 在所有迭代中正确更新数组。这是固定的代码 - 也许有人会遇到类似的问题,所以这里是解决方案:

    import React, {useState, useEffect} from 'react';
    
    function Ingredients() {
      const [heatingStepsTime, setTime] = useState([]);
      const [heatingStepsTimer, setTimer] = useState([]);
    
      function getTimes(i, type) {
        if (type === "time") {
          setTimeout(() => {
            setTime(currentTime => currentTime.concat(i))
          },1000);
        } else {
          setTimeout(() => {
            setTimer(currentTime => currentTime.concat(i))
          }, 1000)
        }
      };
    
      const getProcess = () => {
                    for (let i = 0; i < 3; i++) {
                      getTimes(i, "time");
                      getTimes(i, "timer");
                    }
                }
    
    useEffect(getProcess, []);
    console.log(heatingStepsTime);
    console.log(heatingStepsTimer);
    if (heatingStepsTime[2] && heatingStepsTimer[2] && heatingStepsTime[2] === heatingStepsTimer[2]) {
      console.log("Works!", heatingStepsTime[1], heatingStepsTimer[1])
    }
    
      return (
        <div className="App">
          test
        </div>
      );
    }
    
    export default Ingredients;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-10
      • 1970-01-01
      • 1970-01-01
      • 2021-12-23
      • 1970-01-01
      • 2015-10-22
      • 2017-08-02
      相关资源
      最近更新 更多