0

Hi i have been building a sorting algorithms visualization it works so far but i have a doubt regarding state object. consider the below code:

import React,{Component} from 'react';
import getMergeSortAnimations from './Person/Person';
import bubbleSortAnimations from './Person/BubbleSort';
import './App.css';


class App extends Component{

    state = {
    array: [],
   bar_width:2
 };

componentDidMount() {

  this.generateArray();
} 


generateArray = ()=> {
  const array = [];

 let val = document.querySelector('#size').value;

 if(val<=10)
 {
   this.setState({bar_width:8});
 }
 else if(val<=20 && val>10)
  this.setState({bar_width:7});
else if(val<=50 && val>20)
   this.setState({bar_width:6});
else if(val<=100 && val>50)
  this.setState({bar_width:5});
else if(val<=150 && val>100)
  this.setState({bar_width:3});
else
   this.setState({bar_width:2});



 for (let i = 0; i < val; i++) {
   array.push(this.randomIntFromInterval(5, 450));
   }
 this.setState({array});


  }

 randomIntFromInterval = (min, max)=> {


  return Math.floor(Math.random() * (max - min + 1) + min);
 }
 mergeSort = ()=>{
   let t ;
   console.log(this.state);

   const animations = getMergeSortAnimations(this.state.array);
   console.log(this.state);
   for (let i = 0; i < animations.length; i++) {

   const arrayBars = document.getElementsByClassName('element');

   const isColorChange = i % 3 !== 2;
   if (isColorChange) {
     const [barOneIdx, barTwoIdx] = animations[i];
     const barOneStyle = arrayBars[barOneIdx].style;
     const barTwoStyle = arrayBars[barTwoIdx].style;
     const color = i % 3 === 0 ? 'red' : '#007bff';
     setTimeout(() => {
       barOneStyle.backgroundColor = color;
       barTwoStyle.backgroundColor = color;
     }, i*10);
   } else {
     setTimeout(() => {
       const [barOneIdx, newHeight] = animations[i];
       const barOneStyle = arrayBars[barOneIdx].style;
       barOneStyle.height = `${newHeight}px`;
     }, i*10);
   }

 }

}



render() {

 return (
  <div>
   <header>
      <input className="slider" onChange={this.generateArray}  type="range" min="5" max="200" 
 id='size'/>
      <nav>
       <ul>
         <li><button onClick={this.generateArray} id="new"  >New array</button></li>
         <li><button onClick={this.mergeSort} id="mergesort" >Merge Sort</button></li>
         <li><button onClick={this.bubbleSort} id="bubbleSort" >Bubble sort</button></li>
       </ul>
     </nav>
    </header>

   <div className="container">
   <br></br>
     {this.state.array.map((value, idx) => (
       <div
         className="element"
         key={idx}
         style={{
           width:`${this.state.bar_width}px`,
           height:`${value}px`
         }}></div>
     ))}

   </div>
   </div>
 );
  }
}

Merge sort Code:

   export default function getMergeSortAnimations(array) {

  const animations = [];
  mergeSort(array, 0, array.length - 1,animations);
  return animations;
  }

function mergeSort(array,low, high,animations) {
 if(low<high)
  {
    const mid = Math.floor((low + high) / 2);
     mergeSort(array, low, mid,animations);
     mergeSort(array, mid + 1, high,animations);
    merge(array, low, high,animations);
  }
 }

 function merge(array,low,high,animations) {
     let a = [];
    let k = low;
    let i = low;
   let mid = Math.floor((low+high)/2);
    let j = mid + 1;
   while (i <= mid && j <= high) {
     animations.push([i, j]);

    animations.push([i, j]);
     if (array[i] <= array[j]) {
      animations.push([k, array[i]]);
      a[k++] = array[i++];
    } else {
     animations.push([k, array[j]]);
     a[k++] = array[j++];
   }
}
   while (i <= mid) {
    animations.push([i, i]);

   animations.push([i, i]);

    animations.push([k, array[i]]);
     a[k++] = array[i++];
   }
  while (j <= high) {
      animations.push([j, j]);

   animations.push([j, j]);

   animations.push([k, array[j]]);
   a[k++] = array[j++];
 }
 for(let o=low;o<k;o++)
 {
   array[o] = a[o];
 }
 }

The merge sort function is under src->Person->Person as mentioned in the import section,it just returns animations array which i use for visualization.

Now the generateArray function generates an array and sets it to state using setSate() Method.When this is done the user can select mergesort and the code runs.But as you can see getMergesortAnimations() returns the animations array after the actual mergesort happens.But the question is:

"""When i console the state array before calling getMergesortAnimations() it displays a sorted array.It happens even before the mergesort is called and how is the state set to the sorted array without acutally using setState method?""" This is very confusing to me .... Thanks. // From Generate random number between two numbers in JavaScript

export default App;

1 Answers1

0

From a quick look at your code I can see that at the very end of your mergeSort function you are doing:

for(let o=low;o<k;o++)
{
  array[o] = a[o];
}

Which is modifying the array in place. So after you in your component call:

const animations = getMergeSortAnimations(this.state.array);

this.state.array will be modified in place. This is something you should not do in React, from React docs:

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

In order to fix this just fix the last couple lines of your mergeSort function so that it does not assign to array but rather creates a new array and returns that.

Ján Jakub Naništa
  • 1,880
  • 11
  • 12