React component not getting rendered each time when state changed

am trying to sort an array using bubble sort and at each step of sort I want to render the change in position of values inside an array. So made the below algorithm with React, at very first time it does render the changes but then gets stop, doesn’t render anything. I tried to console log the array I am rendering in and I am getting the each sort step on console but don’t know why it is not working here. Can anybody please tell me why it’s happening so? also what can be done?

Note: It was working fine and rendering the sorted array initially, but later when I added setTimeOut function it is not working.

App.js

import React, { useState } from "react";

const App = () => {
  const [arrayForSort, setArrayForSort] = useState([44,2,46,11,15,34,1,7,55]);

  const fetchArray = arrayForSort.map((element) => {
    return <span>{element} </span>;
  });

  const bubbleSort = (array) => {
    let newArray = [...array];
    let n = newArray.length;

    for (let i = 0; i < n; i++) {
      for (let j = 0; j < n - i; j++) {
        const myVar = setTimeout(() => {
          if (newArray[j] > newArray[j + 1]) {
            [newArray[j], newArray[j + 1]] = [newArray[j + 1], newArray[j]];
          }
          console.log(newArray);   // render each step of sort 
          setArrayForSort(newArray);   // on screen it just shows "2 44 46 11 15 34 1 7 55" the very first step of sort
        }, 2000);
      }
    }
  };

  return (
    <div>
      <h4>Array: </h4>
      <span>{fetchArray}</span>
      <div>
        <button
          onClick={() => {
            bubbleSort(arrayForSort); 
          }}
        >
          Sort
        </button>
      </div>
    </div>
  );
};

export default App;

Why are you doing the timeout? That makes no sense to me. Get rid of that. Also, I wouldn’t change the state on each pass of the sort - make a copy, sort that, then set the state at the end. Also, add a key to your mapped elements so React knows when things have changed.

When I do those three things, it works fine for me.

1 Like

I’m guessing the idea is to show each stage of the sort?

Didn’t really think much about it or test anything. But you might be able to do it in stages and use a useEffect to trigger a re-render every time the dependency changes.

1 Like

The problem is that you set one timeout for all, simultaneously. You’d have to create a variable that increments by one in each loop, to count the steps, and set each time to 2000 * step.

1 Like

Yeah, I guess I see that. Yeah, I agree with jsdisco’s suggestion or something like that - they were just piling up on top of each other and there might have been some kind of closure/non-closure problem with all that data.

Just tested that, it doesn’t work because of this:

setArrayForSort(newArray);

React thinks the array hasn’t changed (because it hasn’t, it’s still referencing the original array). So additionally to introducing a step variable, you’d have to change the above to

setArrayForSort([...newArray]);

Hi @kevinSmith, I have added timeout so that there will be delay of 2 seconds each but, I realized now that the timeout should be incremented in each step.
Thanks for the help.

@jsdisco yes, now I have realized that all the setTimeout s are fired together after 2 seconds, it has to be incremented each time.
Thanks for the help.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.