React Rerender dynamic Components (Solr)

2019-08-26 15:46发布

问题:

I am somewhat new to ReactJS

I have a react class that is rendering a number of items: (Sample)

    var app = app || {};

app.Results = React.createClass({


    componentDidMount: function () {

    },

    handleUpdateEvent: function(id){


        var _self = this;

        var handler = function()
        {
            var query = _self.props.results.query;
            _self.props.onSearch(query); // re-does the search to re-render items ... 
            // obviously this is wrong since I have to click the button twice to see the results
            //
        }
        var optionsURL = {dataType: 'json'};
        optionsURL.type= 'POST';
        optionsURL.url = 'http://localhost:8983/solr/jcg/dataimport?command=delta-import&clean=false&commit=true&json.nl=map&wt=json&json.wrf=?&id='+id;
        // updates index for specific item.

        jQuery.ajax(optionsURL).done(handler);

    },


    render: function () {
        var tdLabelStyle = {
            width: '150px'

        } 
        return (
            <div id="results-list">

                {this.props.results.documents.map(function (item) {

                    return (
                        <div id={item.id} key={item.id} className="container-fluid result-item">
                            <div className="row">
                                <div className="col-md-6">
                            <table>
                                <tr><td colspan="2">{item.name}</td></tr>
                                <tr style={{marginTop:'5px'}}><td style={tdLabelStyle}><b>Amount:</b></td><td>{item.amount}&nbsp;&nbsp;
                                    <button type="Submit" onClick={() => {this.handleUpdateEvent(item.id)}}  title="Refresh Amount" >Refresh</button>
                                </td></tr>

                            </table>
                                </div>

                            </div>
                        </div>

                    )

                },this)}            

            </div>
        );
    }
});

I have a button within the table that makes a call out to SOLR to perform a delta import, then re-calls the select function in order to grab the new data. I'm obviously doing the handleUpdateEvent function incorrectly, however, I'm not 100% sure how to go about getting either the entire thing to re-render, or just the individual item to re-render.

(Hopefully I've made sense...)

Any help is appreciated.

(onSearch Function)

 handleSearchEvent: function (query) {

                if (this.state.query != null)
                    {
                        if (this.state.query.filters != null)
                            {
                                query.filters = this.state.query.filters;
                            }
                    }
                $("#load-spinner-page").show();
                if (app.cache.firstLoad) {
                    $("body").css("background","#F8F8F8");
                    app.cache.firstLoad = false;
                }
                var _self = this;
                app.cache.query = query;
                docSolrSvc.querySolr(query, function(solrResults) {
                    _self.setState({query: query, results: solrResults});
                    $("#load-spinner-page").hide();
                });

            },

回答1:

The first thing to change is the use of React.createClass. This has been depracated in favour ES6 syntax. Also, I dont't suggest using jQuery along side React. It's not impossible to do, but there are other things to consider. Read this for more. I'll use it here, but consider something like fetch or axios (or one of the many other libraries) for fetching the data.

I think you're on the right track, but a few things to update. Because the available options are changing, I would put them into the components state, then having the handleUpdateEvent function update the state, which will trigger a re-render.

Your class would look something like this:

class Results extends React.Component {
  constructor(props) {
    super(props);

    // this sets the initial state to the passed in results
    this.state = {
      results: props.results
    }
  }

  handleUpdateEvent(id) {
    const optionsURL = {
      dataType: 'json',
      type: 'POST',
      url: `http://localhost:8983/solr/jcg/dataimport?command=delta-import&clean=false&commit=true&json.nl=map&wt=json&json.wrf=?&id=${ id }`
    };

    // Instead of calling another function, we can do this right here.
    // This assumes the `results` from the ajax call are the same format as what was initially passed in
    jQuery.ajax(optionsURL).done((results) => {
      // Set the component state to the new results, call `this.props.onSearch` in the callback of `setState`
      // I don't know what `docSolrSvc` is, so I'm not getting into the `onSearch` function
      this.setState({ results }, () => {
        this.props.onSearch(results.query);
      });
    });
  }

  render() {
    const tdLabelStyle = {
      width: '150px'
    };

    // use this.state.results, not this.props.results
    return (
      <div id="results-list">
        {
          this.state.results.documents.map((item) => (
            <div>
              <div id={ item.id } key={ item.id } className="container-fluid result-item">
                <div className="row">
                  <div className="col-md-6">
                    <table>
                      <tr><td colspan="2">{item.name}</td></tr>
                      <tr style={{marginTop:'5px'}}>
                        <td style={ tdLabelStyle }><b>Amount:</b></td>
                        <td>{item.amount}&nbsp;&nbsp;
                          <button type="button" onClick={ () => { this.handleUpdateEvent(item.id) } }  title="Refresh Amount" >Refresh</button>
                        </td>
                      </tr>
                    </table>
                  </div>
                </div>
              </div>
            </div>
          ))
        }
      </div>
    );
  }
}