【问题标题】:Rendering every iteration of an array sort in React在 React 中渲染数组排序的每次迭代
【发布时间】:2020-06-25 22:52:14
【问题描述】:

我正在尝试在 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 渲染,但为简洁起见将其排除在外

【问题讨论】:

    标签: reactjs sorting state


    【解决方案1】:

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

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

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

    这里是working implementation使用这个方法:

    (这是用 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]; 时,原始数组(在您的状态下)被更新。如果你用inputArr 调用 setState,React 会将它与dataSet 进行比较。由于您已修改 dataSet,因此值将匹配 inputArr,这意味着状态不会更新。

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

    const data = [...oldData]

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

    【讨论】:

    • 你能解释一下这一行吗: const { i, j, key, data: oldData } = this.state;即您如何定义尚未处于状态的键并且您正在设置尚未创建的 data= oldData?
    • key 是状态的可选成员,意思是当您在分配之前检索它时,它将返回未定义。我们可以在这里利用这种行为来测试我们是否处于排序的中途。一旦排序交互完成,您可以看到 key 被重新分配为 undefined。当destructuring an object 时,这是重命名变量的语法:{data: oldData}。所以在这里我将状态变量数据分配给一个名为oldData的新变量
    猜你喜欢
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    • 2019-10-06
    • 2021-10-28
    相关资源
    最近更新 更多