Refreshing children state from parent React

My approach is that you should have structure something like this in parent's render:

<ParentView>
{ this.props.rows.map(function(row) {
    <ChildRow props={row.props} />
  }).bind(this)
}
</ParentView>

And then on row.props you have the information whether current row item is checked or not. When parent checkbox is toggled, you populate all the row.props with the status.

On child, you will receive those with componentWillReceiveProps and you do the magic (e.g. set the correct state) when checkbox is toggled:

componentWillReceiveProps: function(props) {
  this.setState({isChecked: props.isChecked});
}

(Info from the React's docs: Calling this.setState() within this function will not trigger an additional render.)

Child element's render would be something like:

<div>
  <input type='checkbox' checked={this.state.isChecked} />
  <label>{this.props.label}</label>
</div>

You can solve this by storing the checked state of all child elements in the parent only. The children set their checked status based on props only (they don't use state for this) and call a callback supplied by the parent to change this.

E.g., in the child:

render: function() {
    //... not showing other components...
        <input type="checkbox"
               value={this.props.value}
               checked={this.props.checked}
               onClick={this.props.onClick}>
}

The parent supplies the onClick, which changes the checked status of the child in its state and passes this back to the child when it re-renders.

In the parent:

getInitialState: function() {
    return {
        allChecked: false,
        childrenChecked: new Array(NUM_CHILDREN) // initialise this somewhere (from props?)
    }
},

render: function() {
    return <div>
               <input type="checkbox" checked={this.state.allChecked}>
               {children.map(function(child, i) {
                   return <Child checked={this.state.childrenChecked[i]}
                                 onClick={function(index) {
                                     return function() {
                                         // update this.state.allChecked and this.state.childrenChecked[index]
                                     }.bind(this)
                                 }.bind(this)(i)}
                          />
                }).bind(this)}
           </div>;
}

-- not checked for typos etc.


Please see the react documentation on Lifting State Up. In your child component, you need to use the props. To update the prop, you need to provide an update function from the parent.