在冒泡排序算法的每一步后重新渲染

React re render after each step of bubble sort algo

好的,所以我想在冒泡排序的每一步之后重新渲染我正在显示的栏。但到目前为止,我的函数只会在所有排序后重新呈现。有人可以建议处理此问题的正确方法吗?

  function bubbleSort(array: number[]) {
    var i;
    var j;
    for (i = 0; i < array.length; i++) {
      // Last i elements are already in place
      for (j = 0; j < array.length - i - 1; j++) {
        // Checking if the item at present iteration
        // is greater than the next iteration

        if (array[j] > array[j + 1]) {
          // If the condition is true then swap them
          var temp = array[j];
          array[j] = array[j + 1];
          array[j + 1] = temp;
        }
        alert(array);
        setTimeout(() => {
          forceUpdate();
        }, 2000);
      }
    }
  }

import { IonButton, IonInput } from '@ionic/react';
import React, { useState, useRef, useEffect } from 'react';
import './Sort.css';

interface ContainerProps {
  name: string;
}

//try force updatae
function useForceUpdate() {
  let [value, setState] = useState(true);
  return () => setState(!value);
}

const Sort: React.FC<ContainerProps> = ({ name }) => {
  //demo force uppdatge
  let forceUpdate = useForceUpdate();

  // param for the number of elements taht will be in the array
  const [numberOfElements, setNumberOfElements] = useState(5);

  //   repeat value so that no style changes when main value is changes
  const [numberOfElementsStyleInput, setNumberOfElementsStyleInput] =
    useState(numberOfElements);

  //   param for the array itself
  const [arrayOfElements, setArrayOfElements] = useState<number[]>([]);

  //ref to outer block for divention retrivals
  const outerUnit = useRef() as React.MutableRefObject<HTMLDivElement>;

  //ref for dynamic scalling of outer-unit by getting container size params
  const containerRef = useRef() as React.MutableRefObject<HTMLDivElement>;

  //const to hold max after each new array gen
  const [max, setMax] = useState<number>(0);

  let myRefs: any = useRef([]);

  // test useState for div dimentions
  const [_heigth, set_heigth] = useState(0);

  // generate array oif random number in range of block size and of count user input
  const generateArrayOfnumbers = (numOfElements: number): number[] => {
    let tempArray: number[] = [];

    for (let index = 0; index < numOfElements; index++) {
      let num: number = Math.floor(Math.random() * 47 + 3);
      tempArray[index] = num;
    }

    return tempArray;
  };

  //get max value of array for scale neededs
  function getMax(array: number[]) {
    return array.reduce((a, b) => {
      return Math.max(a, b);
    });
  }

  function wait(ms: any) {
    var start = new Date().getTime();
    var end = start;
    while (end < start + ms) {
      end = new Date().getTime();
    }
  }

  //n^2
  // Creating the bblSort function
  function bubbleSort(array: number[]) {
    var i;
    var j;
    for (i = 0; i < array.length; i++) {
      // Last i elements are already in place
      for (j = 0; j < array.length - i - 1; j++) {
        // Checking if the item at present iteration
        // is greater than the next iteration

        if (array[j] > array[j + 1]) {
          // If the condition is true then swap them
          var temp = array[j];
          array[j] = array[j + 1];
          array[j + 1] = temp;
        }
        alert(array);
        setTimeout(() => {
          forceUpdate();
        }, 2000);
      }
    }
  }
  //Main return
  return (
    <div className="container" ref={containerRef}>
      <strong>{name}</strong>

      <div
        id="outer-unit"
        className="outer-unit-class"
        ref={outerUnit}
        style={
          window.innerHeight > 1024
            ? {
                height: window.innerHeight * 0.6 + 'px',
                width: window.innerWidth * 0.6 + 'px',
                position: 'relative',
              }
            : {
                height: window.innerHeight * 0.4 + 'px',
                width: window.innerWidth * 0.65 + 'px',
                position: 'relative',
              }
        }
      >
        {/* {arrayOfElementsHeights.map((current_h, index) => {
          let temp_array_H: number[] = [];

          return setArrayOfElementsHeights();
        })} */}
        {arrayOfElements.map((currentElement, index) => {
          return (
            <div
              ref={(ele: any) => (myRefs.current[index] = ele)}
              key={index}
              id={'inner-unit-' + index}
              className="inner-unit-class"
              block-value={arrayOfElements[index]}
              style={{
                position: 'absolute',
                left:
                  (outerUnit.current.clientWidth / numberOfElementsStyleInput) *
                    index +
                  'px',
                bottom: '0',
                marginLeft: outerUnit.current.clientWidth * 0.006,
                marginRight: outerUnit.current.clientWidth * 0.0015,
                height:
                  outerUnit.current && max
                    ? ((outerUnit.current.clientHeight -
                        outerUnit.current.clientHeight * 0.1) /
                        max) *
                        arrayOfElements[index] +
                      _heigth +
                      'px'
                    : '',
                width: outerUnit.current
                  ? outerUnit.current.clientWidth / numberOfElementsStyleInput -
                    (outerUnit.current.clientWidth / 100) * 1.5 +
                    'px'
                  : '',
                backgroundColor: '#db7420',
              }}
            >
              <h3>{arrayOfElements[index]}</h3>
            </div>
          );
        })}
      </div>
      <IonInput
        type="number"
        value={numberOfElements}
        placeholder="Enter Number"
        className="input-num"
        onIonChange={(e) => setNumberOfElements(parseInt(e.detail.value!, 10))}
      ></IonInput>
      <IonButton
        onClick={() => {
          const data = generateArrayOfnumbers(numberOfElements);
          setArrayOfElements(data);
          setMax(0);
          setMax(getMax(data));
          setNumberOfElementsStyleInput(numberOfElements);
        }}
      >
        Random generate
      </IonButton>
      <IonButton
        onClick={() => {
          bubbleSort(arrayOfElements);
        }}
      >
        Bubble Sort
      </IonButton>
      <section className="info-section">
        <h1>Bubble Sort algorithm using JavaScript</h1>
        <p>
          Bubble sort algorithm is an algorithm that sorts the array by
          comparing two adjacent elements and swaps them if they are not in the
          intended order. Here order can be anything like increasing order or
          decreasing order.
        </p>
        <h2>How Bubble-sort works</h2>
        <p>
          We have an unsorted array arr = [ 1, 4, 2, 5, -2, 3 ] the task is to
          sort the array using bubble sort. Bubble sort compares the element
          from index 0 and if the 0th index is less than 1st index then the
          values get swapped and if the 0th index is less than the 1st index
          then nothing happens. then, the 1st index compares to the 2nd index
          then the 2nd index compares to the 3rd, and so on…
        </p>
      </section>
      <br />
    </div>
  );
};

export default Sort;

更新:

  async function bubbleSort(array: any) {
    let isSorted = false;
    while (!isSorted) {
      isSorted = true;
      for (let i = 0; i < array.length - 1; i++) {
        if (array[i] > array[i + 1]) {
          [array[i], array[i + 1]] = [array[i + 1], array[i]];
          isSorted = false;

          setTimeout(() => {
            setArrayOfElements(array.slice());
          }, 2000);
        }
      }
    }
    return array;
  }

bubbleSort(arrayOfElements.slice());

因此,一般来说,React 组件会在输入 Props 更改或挂钩更改时重新呈现。您正在对数组进行排序,并在此过程中改变 arrayOfElements。只要您使用 setArrayOfElements.

,您的组件就会呈现正确的状态

快速查看您的示例,我会说有两个步骤可以解决您的问题。

  1. 避免通过创建输入数组的副本来直接改变状态数组,例如使用切片 api
onClick={() => {
  bubbleSort(arrayOfElements.slice());
}}
  1. 在冒泡排序函数中更新您的状态
 ...
 alert(array);
 setArrayOfElements(array.slice();
 ...

请注意,更新状态将覆盖您的初始数组,这可能不是您想要的。在这种情况下,我建议您创建两个状态变量,一个用于保存未排序的数组,另一个用于保存当前状态。

强制更新只是一个 hack,这不是解决 React 中重新渲染问题的正确解决方案,因此您可以将其删除。

此外,您需要使 buble 排序异步,并可能在迭代之间添加有意义的超时。如果函数不是异步的,您将看不到任何逐渐的状态变化,因为下一个状态将在冒泡排序函数完成后呈现。

好的,这是我最终得到的解决方案:

  // encapsulate setTimeout in a promise, so we can await it below
  const wait = (timeout: any) => {
    return new Promise((resolve) => {
      setTimeout(resolve, timeout);
    });
  };

  //n^2
  // Creating the bblSort function
  async function bubbleSort(array: any) {
    let isSorted = false;
    while (!isSorted) {
      isSorted = true;
      for (let i = 0; i < array.length - 1; i++) {
        if (array[i] > array[i + 1]) {
          [array[i], array[i + 1]] = [array[i + 1], array[i]];
          isSorted = false;

          setArrayOfElements(array.slice());
          await wait(1000);
        }
      }
    }
    return array;
  }

<IonButton
        onClick={() => {
          bubbleSort(arrayOfElements.slice());
        }}
      >