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

4
我一直在尝试将我的Web应用程序中的一个页面从jQuery和Vanilla JS转换为React,但由于我对React不熟悉,所以我卡住了。目前,在该页面上,我有一个HTML表格,其中行与数据库表相关联,并且另有一列带有链接以编辑和删除行。这是通过打开包含表单的Bootstrap模态框来完成的,该表单为编辑操作填充了适当的行,还有一个删除模态框以确认删除,页面上还有一个链接以添加新行,也通过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}来处理ModelNamereturn

2个回答

3
除了Felix Kling的回答之外,您需要以某种方式在ModalNames和ModalName之间进行通信以更新状态,因为状态由ModalNames管理,并且在ModalName中调用事件。
一种解决方案是将更新状态的函数传递给ModalName:
ModalNames:
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,并进行setState操作,就像你最初编写的那样。


1
你需要决定数据的真实来源。在你目前的设置中,它似乎在 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成为一个“dump”组件。它与数据管理无关,只呈现传递给它的数据。
另一个问题是您正在从ModelNamesthis.props.model_names)中读取道具,而不是状态。状态和道具是不同的。您需要从状态(this.state.model_names)中读取,以便组件在状态更改时更新。

哇,感谢Felix的回答 - 非常感谢。现在就去试一下。 - martincarlin87
嗯,我实际上对组件名称感到困惑。我刚才看到你已经在 ModelNames 中使用状态了。让我更新我的答案。 - Felix Kling
是的,没错,抱歉让你感到困惑了,这个泛称名称让事情变得更糟。我在表格组件中使用复数形式,在单个行中使用单数形式。 - martincarlin87
更新了答案。简短的描述但更好的解决方案 :) - Felix Kling
非常感谢,我正准备尝试一下,希望它能够正常工作/我能够弄清楚自己在做什么,然后我会接受这个答案。 - martincarlin87
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接