Reputation: 33
I was working on displaying the steps to sorting an array and trying to render out the different steps in react. When I call my bubble sort function, the array is already sorted after I click the button.
Creating my state variable:
const [arr, setArr] = useState(resetArr())
function resetArr() {
return new Array(10).fill().map(() => {
return ({
num: Math.floor(Math.random() * 100),
eval: false
})})
}
Bubble sort function
function bubbleSort() {
const history = [];
const sArr = arr.slice();
let len = sArr.length;
for (let i = len-1; i >= 0; i--) {
for (let j = 1; j<=i; j++) {
if (sArr[j-1].num > sArr[j].num) {
const temp = sArr[j-1].num;
sArr[j-1].num = sArr[j].num;
sArr[j].num = temp;
}
history.push(sArr);
}
}
console.log(history)
}
Button and return
return (
<div>
<div className="arr-container">
{arr.map((item, idx) =>
<div key={idx} className="arr-item">
{item.num}
</div>
)}
</div>
<div>
<button onClick={() => bubbleSort()}>Bubble</button>
</div>
</div>
)
Console log for history
0: Array(10)
0: {num: 0, eval: false}
1: {num: 3, eval: false}
2: {num: 9, eval: false}
3: {num: 18, eval: false}
4: {num: 33, eval: false}
5: {num: 41, eval: false}
6: {num: 53, eval: false}
7: {num: 65, eval: false}
8: {num: 94, eval: false}
9: {num: 99, eval: false}
1: Array(10)
0: {num: 0, eval: false}
1: {num: 3, eval: false}
2: {num: 9, eval: false}
3: {num: 18, eval: false}
4: {num: 33, eval: false}
5: {num: 41, eval: false}
6: {num: 53, eval: false}
7: {num: 65, eval: false}
8: {num: 94, eval: false}
9: {num: 99, eval: false}
Any help is appreciated, I am completely stuck on why it's working like this.
Upvotes: 1
Views: 153
Reputation: 11
I don't know if this will be helpful at all, but I decided I might as well link it: sandbox!
I thought it would be nice to have the rendering portion implemented so it would be easier to see what is happening to the data.
Upvotes: 0
Reputation: 11771
You need to understand object references in JavaScript and programming languages in general.
As an example:
const array = [];
const someObject = {
a: "foo"
};
array.push(someObject);
someObject.a = "bar";
array.push(someObject);
console.log(JSON.stringify(array, null,2));
This doesn't print:
[
{
"a": "foo"
},
{
"a": "bar"
}
]
it prints:
[
{
"a": "bar"
},
{
"a": "bar"
}
]
Because in that first push to the array, you aren't pushing the object as it is at the time, you are pushing a reference to the object.
In this scenario, when you later change the objects a
property, (you mutate the object) that value changes in the array.
This kind of confusion is why people like to avoid property reassignment like this, why immutable programming is a thing.
Your code basically has the same problem.
You are pushing the same array to the history array each time it loops, and then you are later mutating that array.
If you change your history.push line to this:
history.push(JSON.parse(JSON.stringify(sArr)));
This solves your problems.
What the parse-stringify does is just clones the array object, ie, it creates a new array object.
Upvotes: 1