Reputation: 179
I 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;
Upvotes: 1
Views: 171
Reputation: 11297
There are few problems in your code. 2000
is a constant value, meaning all your setTimeout
s are fired together after 2 seconds. That's why all your console.logs
appear at the same time.
Secondly, setTimeout
will retain the reference of setArrayForSort
. But you need a new reference after each render. This could work if you use class components but with functional component you need to think differently.
Here is a working demo codesandbox link
import React, { useEffect, useRef, useState } from "react";
const App = () => {
const [arrayForSort, setArrayForSort] = useState([44, 2, 46, 11, 15, 34, 1, 7, 55]);
const ijRef = useRef({ i: 0, j: 0 });
const [isSorting, setIsSorting] = useState(false);
const fetchArray = arrayForSort.map((element) => {
return <span key={element}>{element} </span>;
});
useEffect(() => {
if (!isSorting) return;
const ij = ijRef.current;
const i = ij.i;
const j = ij.j;
const arr = [...arrayForSort];
const n = arr.length;
let isSwapped = false;
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
isSwapped = true;
}
if (j < n - i) {
ij.j++;
} else if (ij.i < n) {
ij.j = 0;
ij.i++;
}
// This will trigger the next render
// and loop will continue until ij.i < n
setTimeout(
() => {
if (ij.i >= n) {
setIsSorting(false);
}
setArrayForSort(arr);
},
isSwapped ? 100 : 0 // delay 100ms for a successful swap
);
}, [ijRef, arrayForSort, setArrayForSort, isSorting]);
const beginSort = () => {
ijRef.current.i = 0;
ijRef.current.j = 0;
setIsSorting(true); // begin sorting
};
return (
<div>
<h4>Array: </h4>
<span>{fetchArray}</span>
<div>
<button onClick={beginSort}>Sort</button>
</div>
</div>
);
};
export default App;
Upvotes: 1