Quicksort visualization in ReactJS, state change don’t update DOM

I was given the task to visualize Quicksort at university. I wrote the partition of the algorithm very small-stepped, so that I can visualize every single step well.

My array looks like this:

 const [arr, setArr] = useState([
        {number: 1, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
        {number: 5, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
        {number: 3, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
        {number: 4, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
        {number: 2, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
        {number: 7, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
        {number: 6, isSelectedFromLeftArrow: false, isSelectedFromRightArrow: false, isPivot: false, isSorted: false},
    ])

I added several attributes to each number to be able to see what is happening with the element later when I display it, so that I can color it afterwards.

My problem is now the following. The algorithm itself works and gives me the correct result in the console. However, the display of the bars does not change. Only when I go into the IDE, make a small change and the display changes to the finished result.

In the first step only the sorted element should be colored.

Here is the actual quicksort process:

const newTryQuickSort = async () => {

        let stack = []

        // Zu Beginn nur ein großes Array, welches sortiert werden soll. Von index 0 bis zum letzten Element
        stack.push(0)
        stack.push(arr.length - 1)

        // while(stack[stack.length - 1] >= 0) {

        for (let i = 0; i <= 3; i++) {
            // Erste Element ist die linke Grenze und das zweite Element ist die rechte Grenze
            let rightEnd = stack.pop()
            let leftStart = stack.pop()

            // Sortiere die erste Partition
            const pivotIndex = await newPartition(leftStart, rightEnd)

            console.log("Result from Partition: " + pivotIndex)

            if (pivotIndex - 1 > leftStart) {
                stack.push(leftStart)
                stack.push(pivotIndex - 1)
            }

            if (pivotIndex + 1 < rightEnd) {
                stack.push(pivotIndex + 1)
                stack.push(rightEnd)
            }

            console.log('Stack: ')
            console.log(stack)

            console.log('______________________________________________________')
        }

Here is the partitioning:

const newPartition = async (leftStart, rightEnd) => {

        const pivotValue = arr[rightEnd].number
        const pivotIndex = rightEnd

        const left = leftStart
        // Das pivot element ist das letzt Element, daher muss die Grenze bis eins vorher gehen
        const right = rightEnd - 1

        let pivotIsSorted = false

        while (!pivotIsSorted) {
            // Lass den Linken pfeil laufen
            const leftArrowIndex = await checkFromLeft(left, right, pivotValue, pivotIndex)

            console.log('leftArrowIndex: ' + leftArrowIndex)

            // Wenn null rauskommt, gab es nur ein Element, welches dann sortiert ist.
            if (leftArrowIndex === null) {
                pivotIsSorted = true
                return leftArrowIndex
            }

            // Überprüfen, ob null zurückkommt, da dann das Array bereits sortiert ist

            //Lass den rechten Pfeil laufen
            const rightArrowIndex = await checkFromRight(left, right, pivotValue, leftArrowIndex)

            console.log('rightArrowIndex: ' + rightArrowIndex)

            // Wenn beide ein Element gefunden haben, welches nicht passt und sie sich nicht getroffen haben,
            // dann tausche sie, setzte leftStart und rightStart neu und beginne von vorne
            if (leftArrowIndex !== rightArrowIndex) {
                await swap(leftArrowIndex, rightArrowIndex, false)
                leftStart = leftArrowIndex
                rightEnd = rightArrowIndex
            }

            // Beide pfeile haben sich getroffen (indexLeft === indexRight)
            // Tausche die stelle, wo sich die Pfeile getroffen haben mit dem pivot und gebe das/die neue/neuen subarray/s zurück
            if (leftArrowIndex === rightArrowIndex) {
                await swap(leftArrowIndex, pivotIndex, true)
                pivotIsSorted = true

                // Das Pivot element liegt nach dem swapt an der Stelle von leftArrowIndex
                return leftArrowIndex

            }
        }

    }

const checkFromLeft = async (start, end, pivot, pivotIndex) => {

        console.log('checkFromLeft: start, end, pivot')
        console.log(start, end, pivot)

        // Wenn das subarray, welches sortiert werden soll nur 1 Element groß ist, ist es fertig sortiert
        if (start === end) {
            // Vertausche die beiden an der gleichen Stelle, um es als sortiert zu setzten
            console.log('Im hear')
            await swap(start, end, true)

            // Gebe 'null' zurück, um zu sagen, dass das subarray nur ein element groß ist
            return null
        }


        // Ansonsten gehe von links nach rechts alle Elemente durch und suche nach einem Element, welches größer ist als das pivot
        for (let i = start; i <= pivotIndex; i++) {

            if (arr[i].number >= pivot) return i

            // Trifft auf den rechten pfeil, welcher noch nicht losgelaufen ist - VORHER
            // Trifft auf das Pivot, somit steht es an der richtigen stelle - NACHHER
            if (i === pivotIndex) return i

        }


    }

const checkFromRight = (start, end, pivot, positionOfLeftArrow) => {


        for (let i = end; i >= start; i--) {

            // Wenn er an der gleichen Stelle ankommt oder der linke schon am Pivot ist, wie der linke Pfeil, gibt er nicht seine, sondern die
            // Position des Linken pfeils zurück (da der linke Pfeil ja auch schon weiter sein kann, als der Rechte)
            if (i <= positionOfLeftArrow) {
                return positionOfLeftArrow
            }

            // Wenn er ein Element gefunden hat, was kleiner als das pivot ist, gibt er es zurück
            if (arr[i].number <= pivot) {
                return i
            }


        }

    }

Here is the swapping of the two elements:

const swap = async (left, rightOrPivot, isPivot = false) => {

        setArr((prevArr) => {

            // Tausche beide Werte aus
            const oldLeft = prevArr[left]
            prevArr[left] = prevArr[rightOrPivot]
            prevArr[rightOrPivot] = oldLeft

            console.log('NewArray after swap: ')
            console.log(prevArr)

            // Wenn das Pivot verschoben wurde, so ist es nun an seiner Finalen Position
            if (isPivot) {
                prevArr[left].isPivot = false
                prevArr[left].isSorted = true
            }

            return prevArr
        })
        
        await sleep(1000)
        
        return true

    }


    const sleep = (ms) => {
        return new Promise(resolve => setTimeout(resolve, ms))
    }

I use a useEffect to output the array whenever it changes. It is also strange that the array is already sorted at the first output.

 useEffect(() => {
        console.log("Arr: ")
        console.log(arr)
    }, [arr])

Here is a screenshot of the console:
Image of the visualization and console

I hope you can help me there.