Jay Jay - 7 months ago 24
Javascript Question

React.js state confusion

I am still trying to understand the state concept in react.js. Can anyone please help with the below jsfiddle? I am trying to filter the records based on the category selected.

var App = React.createClass({
render: function() {
return (
<div>
<Instructions />
<h1>Requests</h1>
</div>
);
}
});

Answer

From what I've found with react, communicating changes between components that don't have a parent-child relationship kind of requires the state to be managed in a top-level component that is a parent to both the components that are trying to communicate. In your example, App is your top-level component that contains MySelect and DisplayRecords as children. If you want the status of MySelect to affect the rows shown in DisplayRecords, you'll have to manage that in the state of App.

In the example, I moved the select box' selection to the state of App, and passed props to the different components accordingly. I tried my best to explain the notable changes with comments, but if you have questions about any changes, definitely leave a comment!

var DisplayRecords = React.createClass({
  render: function(){
    var _this = this; // avoid conflicting this keyword
    return (
        <div>
        <table><tbody> // include tbody to avoid errors (weird react thing)
         {_this.props.records.map(function(record){ // loop through each record
            // if all records is selected, or the record status matches the selection
            if(_this.props.filter=="All Requests" || record.status == _this.props.filter){
              // return the record as a table row
              return (
                <tr key={record.id} >
                <td>{record.title}</td>
                <td><a href="#">{record.status}</a></td>
                <td>{record.updated_at}</td>
                <td>{record.created_at}</td>
                <td><a href="#">Delete</a></td>
                </tr>
              )
            }
          })}
        </tbody></table>
     </div>
    )
  }
});

var MySelect = React.createClass({
  callParentFunction: function(e) {
    // call parent's getFilter function with the selected option's text as argument
    this.props.changeHandler(e.target.options[e.target.selectedIndex].text);
  },
  render: function() {
    // note removed specified value of select box
    return (
      React.createElement("select", { onChange: this.callParentFunction},
         React.createElement("option", { value: 1 }, "All Requests"),
         React.createElement("option", { value: 2 }, "Approved"),
         React.createElement("option", { value: 3 }, "Denied"),
      React.createElement("option", { value: 4 }, "Pending")
      )
    )
  }
});


var App = React.createClass({

  getInitialState: function(){
    // set initial selection
    return {
     selected: "All Requests"
    }
  },
  getFilter:function(newFilter){
    // set new selection on change of select box
    this.setState({selected: newFilter})
  },
  render: function() {
    // pass selected state to both MySelect and DisplayRecords
    // pass getFilter to MySelect so it can be called onChange
    return (
      <div>
        <MySelect selection={this.state.selected} changeHandler={this.getFilter} />
        <h1>Requests</h1>
          <DisplayRecords records={this.props.data} filter={this.state.selected} />
      </div>
    );
  }
});
React.render(<App data={requests}/>, document.getElementById('container'));
Comments