最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React - How to Update State After AJAX Request - Stack Overflow

programmeradmin0浏览0评论

I've been tinkering with converting one page in my web application to use react rather than jQuery and Vanilla JS but I'm getting stuck on how to approach it because of how unfamiliar I am with react.

At the moment, on the page I have an html table with rows that relate to a database table and another column with links to edit and delete the rows.

This is done by opening bootstrap modals containing a form which is populated for the appropriate row for the edit action and a delete modal to confirm the deletion, there is also a link on the page to add a new row, also via AJAX, so what I am trying to do is replicate this in react but I can't seem to understand how to go about it.

At the moment I have this (I am using a generic ponent name (ModelName) for this example to avoid confusion from what it is actually called.):

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 es from Rails
  <ModelName model_names={<%= @model_names.to_json %>} />,
  document.getElementById('react')
);

The deletion via ajax works fine and the server side responds with all the rows in the database table (after the deletion has taken place), so the json response is in exactly the same format as the initial data provided on the page load, I am just trying to figure out how to update the state so that react knows to remove the record I just deleted.

Similarly, I want to then extend it to replicate my editing and creation CRUD features but I am struggling to find the information I need after reading a number of blog posts.

Update

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);
  },
  // ...
});

Also, just to try and include everything relevant, the delete button still has onClick={this.handleRemoveModelName} for the ModelName return.

I've been tinkering with converting one page in my web application to use react rather than jQuery and Vanilla JS but I'm getting stuck on how to approach it because of how unfamiliar I am with react.

At the moment, on the page I have an html table with rows that relate to a database table and another column with links to edit and delete the rows.

This is done by opening bootstrap modals containing a form which is populated for the appropriate row for the edit action and a delete modal to confirm the deletion, there is also a link on the page to add a new row, also via AJAX, so what I am trying to do is replicate this in react but I can't seem to understand how to go about it.

At the moment I have this (I am using a generic ponent name (ModelName) for this example to avoid confusion from what it is actually called.):

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 es from Rails
  <ModelName model_names={<%= @model_names.to_json %>} />,
  document.getElementById('react')
);

The deletion via ajax works fine and the server side responds with all the rows in the database table (after the deletion has taken place), so the json response is in exactly the same format as the initial data provided on the page load, I am just trying to figure out how to update the state so that react knows to remove the record I just deleted.

Similarly, I want to then extend it to replicate my editing and creation CRUD features but I am struggling to find the information I need after reading a number of blog posts.

Update

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);
  },
  // ...
});

Also, just to try and include everything relevant, the delete button still has onClick={this.handleRemoveModelName} for the ModelName return.

Share Improve this question edited Feb 24, 2016 at 17:03 martincarlin87 asked Feb 24, 2016 at 16:19 martincarlin87martincarlin87 11.1k24 gold badges103 silver badges147 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

On top of Felix Kling's answer, you would need to somehow municate between the ModalNames and ModalName to update the state, since the state is managed by ModalNames and the event is called in ModalName.

One solution is to pass function that updates the state to the 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} />);
    });
    ...
  }
}

ModalName:

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)
    });
  },
  ...
}

Alternative solution is to define handleRemoveModelName in ModalNames which takes in id, calls ajax, and does setState like you originally had.

You have to decide where the source of truth for your data should be. In your current setup, it appears to be in ModelNames.

Instead of having ModelName perform the deletion, let ModelNames do it, since it owns the data.

Just pass a callback to ModelName that is called when deletion is requested. In this example we are adding a new property to the child ponent, onRemove which is called when the delete button is clicked:

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);
  },
  // ...
});

The parent ponent can then decide how it wants to respond to this and make the appropriate Ajax call.

This makes ModuleName a "dump" ponent. It doesn't have any thing to do with data management and only renders the data it gets passed.


The other issue is that you are reading from the props in ModelNames (this.props.model_names), not the state. State and props are different. You need to read from the state (this.state.model_names) in order for the ponent to update when the state changes.

发布评论

评论列表(0)

  1. 暂无评论