1

I have a component and inside of it I am communicating with API (here I put timeout instead for simulation). I make some calls inside for loop to update arrays on current interation indexes. Finnally I want to console.log all arrays with added data. And here is the problem. Loop is going through all iterations and doesn't wait to finish asynchonous tasks so it's printing empty arrays with annotation that there are data but just came now.

I tried to add useState but I didn't solve the problem.

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;

Is there a way to stop for loop iteration in React so it will continue when asychronous tasks are done?

2
  • @giorgimoniava But how to use it inside for loop? Commented Aug 7, 2019 at 19:35
  • are you using a promise? or async/await? Commented Aug 7, 2019 at 19:36

2 Answers 2

3

Try this

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

Explanation:

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

To simulate the API, you should simulate it with a promise. This timer will resolve the promise when it times out.

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

You want to store your result into a state so that react knows to render the result

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

This is just to simulate your for loop... you may ignore this if you have multiple API calls... just replace it with

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

this will wait for all the promises to resolve and store the result into the state

Sign up to request clarification or add additional context in comments.

Comments

0

I found a solution. In React we need to use useState to update arrays properly through all iterations. Here is fixed code - maybe someone will have similar problem so here is solution:

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.