React 和 jquery-ui/ui/widgets/sortable:子组件未按预期重新排序

React and jquery-ui/ui/widgets/sortable: Child component not reorder as expect

我在名为“portfolios”的父组件的“State”中有一个数组。您可以使用以下方式访问:“this.state.portfolios”.

还有一个名为“StockDetailsComponent”的子组件。

在父组件中,我使用映射函数来呈现子组件“StockDetailsComponent”,如下所示:

  {
    this.state.portfolios.map((obj, key) => {
      return <StockDetailsComponent key={key} portfolio={obj} onRemovePortfolio={this.onRemovePortfolio}/>;
    })
  }

没关系。但是,当我重新排序“this.state.portfolios”时,子组件重新呈现并不像预期的那样。

之前:投资组合 = ["object_stock_symbol_1", "object_stock_symbol_2"];

重新排序后:投资组合 = ["object_stock_symbol_2", "object_stock_symbol_1"];

父组件如下所示,让我解释一下:

 class VndDomain extends React.Component {
  constructor(props) {
    super(props);
    this.socket = null;
    this.sortableEnabled = false;
    this.state = {
      portfolios: []
    };
  }

  render() {
    return (
      <div id="SQ-vnd">
        <HeaderComponent/>

        <div className="SQ-body">
          <div className="SQ-text-right">
            <p className="SQ-d-inline-block SQ-cursor-pointer SQ-mt-5 SQ-mb-5" onClick={this.removeAllPortfolios}>Xóa toàn bộ</p>
          </div>

          <StockFormCreateComponent onCreatePortfolio={this.onCreatePortfolio}/>

          <div id="JSSQ-portfolio">
            {
              this.state.portfolios.map((obj, key) => {
                return <StockDetailsComponent key={key} portfolio={obj} onRemovePortfolio={this.onRemovePortfolio}/>;
              })
            }
          </div>

        </div>

        <FooterComponent/>
      </div>
    );
  }

  componentDidMount() {
    this.enableSortable();
    this.getAllPortfolioByUserId();
  }

  /**
   * Get all portfolios belong to current user
   * @return {Promise} [description]
   */
  getAllPortfolioByUserId = async () => {
    try {
      this.props.dispatch(loadingSpinnerActions.showLoadingSpinner());
      let result = await PortfolioService.getAllPortfolioByUserId();
      if(result.data.status === "SUCCESSFUL") {
        this.setState({portfolios: result.data.data}, () => {
          this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
        });
      } else {
        throw new Error(`${result.data.message}`);
      }
    } catch(error) {
      this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
      CommonUtilities.ShowLog(error.message);
    }
  }

  /**
   * Enable drag and drop to reorder
   * @return {[type]} [description]
   */
  enableSortable = () => {
    let parentEl = $("#JSSQ-portfolio");
    // Check duplicate sortable before set
    if (this.sortableEnabled) {
      parentEl.sortable("destroy");
      parentEl.sortable();
    } else {
      parentEl.sortable();
      this.sortableEnabled = true;
    }

    parentEl.on("sortupdate", async () => {
      let sorted = parentEl.sortable("serialize");
      let newOrderArrObj = sorted.split("&").map((value) => {
        let symbol = value.replace("SQ[]=", "").toUpperCase();
        let portfolio = this.state.portfolios.find(obj => obj.symbol === symbol);
        return {
          _id: portfolio._id,
          symbol
        };
      });

      try {
        this.props.dispatch(loadingSpinnerActions.showLoadingSpinner());
        let result = await PortfolioService.reorderPortfolio({newOrder: newOrderArrObj});
        if(result.data.status === "SUCCESSFUL") {
          this.setState({portfolios: result.data.data}, () => {
            this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
          });
        } else {
          throw new Error(`${result.data.message}`);
        }
      } catch(error) {
        this.setState((prevState) => {
          return {portfolios: prevState.portfolios};
        }, () => {
          this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
        });
      }

    });
  }

首先,我从数据库中获取投资组合列表,分配给客户端中显示的状态“投资组合”。并启用 drag/drop 通过“enableSortable”功能重新排序。此时,它工作正常。

当我拖动重新排序时,“this.state.portfolios”按预期更改,我可以在“console.log()”中看到但子组件渲染错误。不按顺序。

代码很长,大家只需要注意以下我试过的选项: 选项 1:

this.setState({portfolios: result.data.data}, () => {
  this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});

result.data.data是重新排序后的数据,没问题,但是重新渲染就不能正常工作了。

选项 2:如果我用一个空数组清除状态并像下面的代码一样重新设置它,它就可以工作,因为子组件已被“卸载”并重新渲染,而不是像选项 1 那样更新。

 this.setState({portfolios: []}, () => {
   this.setState({portfolios: result.data.data}, () => {
     this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
   });
 });

请帮帮我 :( 我不想先 setState 然后再 setState。

看起来您的投资组合数据是一个复杂的对象,React 无法确定它是否已更改。 Yoiu 可以这样做:

你可以这样做:

let newPrtfolio = Object.assign ([],result.data.data); // Assign data to new object and assign it

this.setState({portfolios: newPrtfolio }, () => {
  this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});

或者如果您的投资组合是一个对象而不是数组,您可以尝试以下方式:

 let newPrtfolio = Object.assign ({},result.data.data); // Assign data to new object and assign it
    
    this.setState({portfolios: newPrtfolio }, () => {
      this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
    });

您可以尝试这两种方法,其中一种方法会根据您的投资组合对象的结构为您解决