首页 > 解决方案 > 在 React 中渲染数组排序的每次迭代

问题描述

我正在尝试在 react 中构建一个简单的应用程序,该应用程序需要一个未排序的数组(this.state.dataset),然后插入对其进行排序并呈现排序过程的每次迭代。

因为 React 是在每次数组更改后异步放置一个 setstate 不起作用。任何想法如何解决这个问题?

我可以通过在每个数组更改后简单地退出函数然后渲染它,然后使用更新的数组重新启动冒泡排序来使用冒泡排序来做到这一点。但是我不能让这种方法在这里工作。我知道效率很低,抱歉我是新手..

render() {
    return (
        <div className="buttons">
          <button onClick={this.sort}>Insertion Sort</button>
        </div>
    );
  }

sort(e) {
    this.myInterval = setInterval(() => {
        let arr = this.insertionSort();
        this.setState({
          dataset: arr,
        });
      }
    }, 1000);
  

insertionSort(e) {
    let inputArr = this.state.dataset
    let length = inputArr.length;
    for (let i = 1; i < length; i++) {
        let key = inputArr[i];
        let j = i - 1;
        while (j >= 0 && inputArr[j] > key) {
            inputArr[j + 1] = inputArr[j];
            j = j - 1;
        return inputArr //Added by me to stop loop and render (probably wrong solution)
        }
        inputArr[j + 1] = key;
    return inputArr //Added by me to stop loop and render (probably wrong solution)
    }
    return inputArr;
};

(我的 render() 方法中有 this.state.dataset 渲染,但为简洁起见排除在外

标签: reactjssortingstate

解决方案


一种可能的解决方案可能是将迭代数组所需的值存储在状态中。在每次修改时,您都可以更新状态并从排序函数返回。

因为 React 在每次数组更改后异步放置一个 setState 是行不通的。任何想法如何解决这个问题?

setState 函数采用状态更新时调用的第二个回调参数。这意味着您可以有效地将状态更新视为同步的。

这是使用此方法的工作实现:

(这是用 React Native 编写的,但逻辑与常规 React 相同)

export default class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      i: 1,
      j: 0,
      data: [...initialData],
    };
  }

  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.data}
          renderItem={({ item }) => <Text>{item}</Text>}
        />
        <Button title="Sort" onPress={this.sort} />
        <Button title="Reset" onPress={this.reset} />
      </View>
    );
  }

  sort = () => {
    const { i, j, key, data: oldData } = this.state;
    const nextSort = () => setTimeout(this.sort, 500);

    if (i == oldData.length) {
      return;
    }

    const data = [...oldData];
    const value = key ? key : data[i];

    if (j >= 0 && data[j] > value) {
      data[j + 1] = data[j];
      this.setState({ j: j - 1, data, key: value }, nextSort);
      return;
    }

    data[j + 1] = value;
    this.setState({ i: i + 1, j: i, data, key: undefined }, nextSort);
  };

  reset = () => this.setState({ data: [...initialData], i: 1, j: 0, key: undefined });
} 

在现有实现中值得一提的最后一件事是状态的突变。当您的状态中有一个数组时,您无法修改该数组,因为这会在您调用 setState 时引起问题。

例如,您的变量dataSet存储在状态中。然后,您使用以下方法设置inputArr状态值的引用dataSet

let inputArr = this.state.dataset

当您现在调用inputArr[j + 1] = inputArr[j];原始数组(在您的状态)时会更新。如果你用inputArrReact 调用 setState ,它将与dataSet. 当您修改后dataSet,值将匹配inputArr,这意味着状态不会更新。

您可以在我的解决方案中看到此问题的解决方法,其中我将 dataSet 复制到一个新数组中:

const data = [...oldData]

这将阻止您所在州的数组更新。


推荐阅读