Search code examples
javascriptreactjssortingsettimeoutvisualizer

Using setTimeout to pause execution to add animations


I am a beginner at react js and am facing difficulty with manipulating DOM elements within functions.
I am trying to build a sorting visualizer using react. For this I have a div consisting of an array using map function:

{array.map((value, index) => (
    <div>
        <div 
            className="bar" 
            key={index} 
            ref = {(value) => this.arrayRef[index] = value}
            style={{height: `${value}px`}}></div>
    </div>
))}

As you can see I have created a ref so that I can animate the transitions using:

this.arrayRef[i].style.backgroundColor = 'blue'

Now when I use a for loop to update the color of the entire array, I get an error saying 'cannot read property style of undefined'. Earlier I was accessing the div bars using document.getElementsbyClassName but after reading a few articles, from what I have gathered so far is that it is better to use refs since document.getElementsbyClassName would give an error if we try to access the DOM before the element has been created.

# this is what i meant 
for(i=0;i<this.arrayRef.length;i++){
    setTimeout(()=>{
        this.arrayRef[i].style.backgroundColor = 'red';
    }, 500)
}

I think the problem might be with the setTimeout here because if I omit out the setTimeout part the color of the entire array changes as required. But I want to show the animation somehow so I want it to pause a little before it colors each element of the entire array instead of just changing the color without any pauses. For this, I thought the setTimeout would be the best option, I tried to use async/await but I am still not fully comfortable with using promises. Any suggestions on what might be going wrong? Any help is much appreciated!


Solution

  • If you want do it one by one, you must increase timer like this:

    for(i=0;i<this.arrayRef.length;i++){
      setTimeout(()=>{
         this.arrayRef[i].style.backgroundColor = 'red';
      }, 500 * i)
    }
    

    setTimeout is async, it doesnt block execution.

    UP: For keep actual i inside setTimeout you must set it as argument:

    for(i=0;i< 10;i++){
      setTimeout(i=>{
         console.log(i);
      }, 500 * i, i)
    }

    In your code all timeouts execute AFTER loop is ended so i contains array.length value:

    for(i=0;i< 10;i++){
      setTimeout(()=>{
         console.log(i);
      }, 500 * i)
    }

    Also you can use let for prevent loosing counter:

    for(let i=0;i< 10;i++){
      setTimeout(()=>{
         console.log(i);
      }, 500 * i)
    }