React - 如何在 AJAX 请求后更新状态

React - How to Update State After AJAX Request

本文关键字:请求 更新 状态 AJAX React      更新时间:2023-09-26

我一直在修补将 Web 应用程序中的一个页面转换为使用 react 而不是 jQuery 和 Vanilla JS,但由于我对 react 的不熟悉,我陷入了如何处理它的困境。

目前,在页面上,我有一个html表,其中包含与数据库表相关的行,另一列包含用于编辑和删除行的链接。

这是通过打开引导模式来完成的,其中包含一个表单,该表单是为编辑操作的相应行填充的,还有一个删除模式以确认删除,页面上还有一个链接可以添加新行,也是通过 AJAX,所以我试图做的是在 react 中复制它,但我似乎不明白如何去做。

目前我有这个(我在这个例子中使用了一个通用组件名称(ModelName),以避免与它的实际名称混淆。

var ModelNames = React.createClass({
  getInitialState: function() {
    return {model_names: this.props.model_names};
  },
  render: function() {
    var rows = [];
    this.props.model_names.forEach(function(model_name) {
      rows.push(<ModelName model_name={model_name} key={model_name.id} />);
    });
    return (
      <div className="row">
        <div className="col-md-12">
          <table className="table table-striped table-bordered table-hover">
            <thead>
              <tr role="row" className="heading">
                <th>Property 1</th>
                <th>Property 2</th>
                <th className="text-center">Options</th>
              </tr>
            </thead>
            <tbody>{rows}</tbody>
          </table>
        </div>
      </div>
    );
  }
});
var ModelName = React.createClass({
  handleRemoveModelName: function() {
    $.ajax({           
      url: '/model_name/ajax_delete', 
      data: { model_name_id: this.props.model_name.id },
      type: 'POST',
      cache: false,           
      success: function(data) {
        this.setState({ model_names: data }); // this is the part I am having trouble with
      }.bind(this),
      error: function() {
        console.log('error');      
      }.bind(this)
    });
  },
  render: function() {
    return (
      <tr id={"model_name_" + this.props.model_name.id}>
        <td>{this.props.model_name.property_1}</td>
        <td>{this.props.model_name.property_2}</td>
        <td className="text-center">
          <a href="javascript:;" className="btn btn-xs" onClick={this.handleEditModelName}><i className="fa fa-pencil"></i></a> <a href="javascript:;" className="btn btn-xs" onClick={this.handleRemoveModelName}><i className="fa fa-remove"></i></a>
        </td>
      </tr>
    );
  }
});
ReactDOM.render(
  // this comes from Rails
  <ModelName model_names={<%= @model_names.to_json %>} />,
  document.getElementById('react')
);

通过 ajax 删除工作正常,服务器端响应数据库表中的所有行(删除发生后),因此 json 响应的格式与页面加载时提供的初始数据完全相同,我只是想弄清楚如何更新状态,以便 react 知道删除我刚刚删除的记录。

同样,我想扩展它以复制我的编辑和创建 CRUD 功能,但在阅读了许多博客文章后,我正在努力找到我需要的信息。

更新

var ModelNames = React.createClass({
  handleRemoveModelName: function(id) {
    $.ajax({           
      url: '/model_name/ajax_delete', 
      data: { model_name_id: id },
      type: 'POST',
      cache: false,           
      success: function(data) {
        this.setState({ model_names: data });
      }.bind(this),
      error: function() {
        console.log('error'); 
      }.bind(this)
    });
  },
  render: function() {
    var rows = [];
    this.props.model_names.map(function(model_name) {
      return (
        <ModelName 
          model_name={model_name}
          key={model_name.id}
          onRemove={this.handleRemoveModelName}
        />
      );
    }, this);
    // ...
   }
});
var ModelName = React.createClass({
  handleRemoveModelName: function() {
    this.props.onRemove(this.props.model_name.id);
  },
  // ...
});

此外,只是为了尝试包含所有相关内容,删除按钮仍然具有onClick={this.handleRemoveModelName} 用于ModelName return

除了 Felix Kling 的回答之外,您还需要以某种方式在ModalNamesModalName之间进行通信以更新状态,因为状态由 ModalNames 管理,并且事件在 ModalName 中调用。

一种解决方案是将更新状态的函数传递给ModalName

模态名称:

var ModelNames = React.createClass({
  ...
  updateState: function(modal_names) {
    this.setState({modal_names})
  },
  render: function() {
    var rows = [];
    this.state.model_names.forEach(function(model_name) {
      rows.push(<ModelName model_name={model_name} key={model_name.id} updateState={this.updateState} />);
    });
    ...
  }
}

模态名称:

var ModelName = React.createClass({
  handleRemoveModelName: function() {
    $.ajax({           
      url: '/model_name/ajax_delete', 
      data: { model_name_id: this.props.model_name.id },
      type: 'POST',
      cache: false,           
      success: function(data) {
        this.props.updateState(data);
      }.bind(this),
      error: function() {
        console.log('error');      
      }.bind(this)
    });
  },
  ...
}

另一种解决方案是在ModalNames中定义handleRemoveModelName,它接受id,调用ajax,并像你最初一样设置状态。

您必须确定数据的真实来源应该在哪里。在您当前的设置中,它似乎处于ModelNames 中。

与其让ModelName执行删除,不如让ModelNames执行删除,因为它拥有数据。

只需将请求删除时调用的回调传递给ModelName即可。在此示例中,我们将向子组件添加一个新属性,单击删除按钮时调用该属性onRemove

var ModelNames = React.createClass({
  handleRemoveModelName: function(id) {
    // make Ajax call here
  },
  render: function() {
    var rows = this.state.model_names.map(function(model_name) {
      return (
        <ModelName 
          model_name={model_name}
          key={model_name.id}
          onRemove={this.handleRemoveModelName}
        />
      );
    }, this);
    // ...
   }
});
var ModelName = React.createClass({
  handleRemoveModelName: function() {
    this.props.onRemove(this.props.model_name.id);
  },
  // ...
});

然后,父组件可以决定它想要如何响应这一点并进行适当的 Ajax 调用。

这使得ModuleName成为"转储"组件。它与数据管理没有任何关系,只呈现它传递的数据。


另一个问题是你从ModelNamesthis.props.model_names)的道具中读取,而不是状态。状态和道具是不同的。您需要从状态(this.state.model_names)读取,以便在状态更改时更新组件。