How to Re-Render in React based on changes to a stately array variable

46 Views Asked by At

I'm trying to build a sorting visualizer similar to this: https://clementmihailescu.github.io/Sorting-Visualizer/ using React.

To handle updating the Canvas with each step in the mergesort algorithm, I'm attempting to use a state variable yHeights (corresponding to the height of each line, to be sorted) and updating the state of this variable during each call to mergesort().

However, I'm running into an infinite loop, I believe because I am not keeping the render() method "pure" - as in, I am updating state during the render method.

How can I refactor this code to properly update the canvas drawing during each call of mergesort()? I think I may be able to use getDerivedStateFromProps to do this, but I'm struggling to understand and implement using the documentation.

Code:

//App.js
import logo from './logo.svg';
import './App.css';
import Controls from './Controls';
import Canvas from './Canvas';
import {useState} from 'react'

var xPositions = []

function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}


function App() {

  const [yHeights, setyHeights] = useState([])

  function merge(left, right) {
    let sortedArr = []; // the sorted elements will go here
  
    while (left.length && right.length) {
      // insert the smallest element to the sortedArr
      if (left[0] < right[0]) {
        sortedArr.push(left.shift());
      } else {
        sortedArr.push(right.shift());
      }
    }
  
    // use spread operator and create a new array, combining the three arrays
    return [...sortedArr, ...left, ...right];
  }

  function mergeSort(arr) {
    setyHeights([arr])
    const half = arr.length / 2;
  
    // the base case is array length <=1
    if (arr.length <= 1) {
      return arr;
    }
  
    const left = arr.splice(0, half); // the first half of the array
    const right = arr;
    return merge(mergeSort(left), mergeSort(right));
  }

  const draw = context => {

  var arrHeights = []
  
  context.fillStyle = "rgb(0, 0, 0)";
  for (var i = 0; i < 100; i+=1) {
    const height = getRandomInt(500) 
    context.fillRect(i * 10, 0, 10, height);
    xPositions.push(i*10);
    arrHeights.push(height)
  }

  setyHeights(arrHeights);

  console.log(yHeights)

};

  return (
    <div className="App">
      <Controls />
      <Canvas draw={draw} numLines={100} />
    </div>
  );
}

export default App;
0

There are 0 best solutions below