【问题标题】:Why doesn't sorting work correctly when I change state?当我更改状态时,为什么排序不能正常工作?
【发布时间】:2020-07-19 11:48:09
【问题描述】:

我有 BubbleSort 组件,但是当我开始排序过程时出现问题并且我的排序工作不正确。我敢肯定,算法本身是正确编写的。我想设置状态过程有问题,但无法弄清楚它可能是什么。

import React, {Component} from "react";
import ArrayView from "../ArrayView/ArrayView";

export default class BubbleSort extends Component{
  state = {
    elements: this.props.elements
  }

    sort = () => {
    const length = this.state.elements.length;
    for (let i = 0; i < length; i++) {
      for (let j = i + 1; j < length; j++) {
        if (this.state.elements[i].value > this.state.elements[j].value) {
          this.swap(i, j);
        }
      }
    }
  }

  swap = (first, second) => {
    this.setState((state) => {
      const newElements = [...state.elements];

      const temp = newElements[first];
      newElements[first] = newElements[second];
      newElements[second] = temp;

      return {
        elements: newElements
      }
    })
  }

  render() {
    const { elements } = this.state;

    return (
      <ArrayView elements={elements} onSort={this.sort} />
    )
  }
}

【问题讨论】:

  • 创建一个可运行的示例很棒,但请使用 Stack Snippets([&lt;&gt;] 工具栏按钮)在此现场进行。 Stack Snippets 支持 React,包括 JSX; here's how to do one.
  • 这个例子有什么问题?每次点击,您似乎都会对算法进行一次迭代
  • 您可以使用Promiseasync-await 语法在每次状态更新之间添加延迟。

标签: javascript reactjs sorting react-state-management


【解决方案1】:

问题是您每次都在状态中交换元素,而在您实际排序的数组中交换它们 sort(本地 elements 数组)。所以后续对sort中的本地elements数组的操作继续使用旧值,这意味着冒泡排序将无法正常工作。

除非您希望您的组件在每次交换时更新 DOM(这意味着对其进行重大更改),否则只需更改一次状态,并在完成排序后设置新数组。

【讨论】:

  • 问题是即使我使用this.state.element 而不是const elements = [...this.state.elements] 我得到相同的结果。 (我相应地编辑了我的问题)。这正是我想要的 - 每次交换都更改状态以动画排序过程。我认为我可以进行两次交换:第一次是在排序函数中,第二次是在交换函数中,实际上是在组件的状态中。但是由于重复,这种方法对我来说似乎很奇怪。有没有办法在没有这种重复的情况下达到这个结果?
  • @RomanAndreev - State updates may be asynchronous and may be batched up。一旦您调用 setState 设置新状态,this.state 就不再是最新的。在您收到状态完成回调(您可以将其作为第二个参数传递给setState 之前,它不会可靠地保持最新状态。此外,您的组件不会在期间重新渲染您的sort 电话。如果您想在进行时显示进度,则必须将冒泡排序的状态保留为状态信息并等到每个状态...
  • ...更改完成,然后再进行下一个更改。这是对您的组件的完全重写。
  • @RomanAndreev - 您可能会发现 my answer here 很有用。它也是关于在 React 组件中显示冒泡排序的进度。我认为上面的答案回答了您提出的问题(为什么它不起作用),并且该答案向您展示了一种方法来做您想做的事情。
【解决方案2】:

由于您想逐步显示排序过程,您可以使用Promiseasync-await 语法在交换后的每次状态更新之间添加延迟。

BubbleSort组件中,添加如下两个函数:

  1. 在交换操作后在每次状态更新之间添加延迟

    sleep(seconds) {
       return new Promise((resolve, reject) => {
           setTimeout(resolve, seconds * 1000);
       });
    };
    
  2. 将在嵌套循环内的每个交换操作之后调用sleep() 函数的排序函数

    async sort() {
      const elements = [...this.state.elements];
      const length = elements.length;
    
       for (let i = 0; i < length; i++) {
         for (let j = i + 1; j < length; j++) {
           if (this.state.elements[i].value > this.state.elements[j].value) {
              const temp = elements[i];
              elements[i] = elements[j];
              elements[j] = temp;
    
             this.setState({ elements });
    
             await this.sleep(1.5);
           }
         }
       }
    };
    

演示:

【讨论】:

    【解决方案3】:

    你不需要在交换函数中设置新的状态。

    在排序函数中交换元素并设置新状态,如下所示:

    sort = () => {
        const elements = [...this.state.elements];
    
        const length = elements.length;
        for (let i = 0; i < length; i++) {
          for (let j = i + 1; j < length; j++) {
            if (elements[i].value > elements[j].value) {
              const temp = elements[i];
              elements[i] = elements[j];
              elements[j] = temp;
            }
          }
        }
        this.setState({ elements });
      }
    

    【讨论】:

    • 感谢您的回答,但这正是我想要的:展示排序过程中的每一步
    • @RomanAndreev,在这种情况下,您的代码可以正常工作,因为单击后,您可以正确地获得排序数组。
    猜你喜欢
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2014-01-31
    • 1970-01-01
    • 2019-09-21
    • 1970-01-01
    相关资源
    最近更新 更多