Moshe Revah Moshe Revah - 1 month ago 6
Javascript Question

How to access child's state in React?

I have the following structure:

FormEditor
- holds multiple FieldEditor
FieldEditor
- edits a field of the form and saving various values about it in it's state

When a button is clicked within FormEditor, I want to be able to collect information about the fields from all
FieldEditor
components, information that's in their state, and have it all within FormEditor.

I considered storing the information about the fields outside of
FieldEditor
's state and put it in
FormEditor
's state instead. However, that would require
FormEditor
to listen to each of it's
FieldEditor
components as they change and store their information in it's state.

Can't I just access the children's state instead? Is it ideal?

Answer

If you already have onChange handler for the individual FieldEditors I don't see why you couldn't just move the state up to the FormEditor component and just pass down a callback from there to the FieldEditors that will update the parent state. That seems like a more React-y way to do it, to me.

Something along the line of this perhaps:

var FieldEditor = React.createClass({ 
  handleChange: function(event) {
    var text = event.target.value;
    this.props.onChange(this.props.id, text);
  },

  render: function() {
    return (
      <div className="field-editor">
        <input onChange={this.handleChange} value={this.props.value}/>
      </div>
    );
  }
});

var FormEditor = React.createClass({
  getInitialState: function() {
    return {};
  },
  handleFieldChange: function(fieldId, value) {
    var newState = {};
    newState[fieldId] = value;

    this.setState(newState);
  },

  render: function() {
    var fields = this.props.fields.map(function(field) {
      var props = {
        id: field, 
        onChange: this.handleFieldChange, 
        value: this.state[field]
      }
      return <FieldEditor {...props} />
    }, this);

    return (
      <div>
        {fields}
        <div>{JSON.stringify(this.state)}</div>
      </div>
    );
  }
});

var App = React.createClass({
  render: function() {
    var fields = ["field1", "field2", "anotherField"];

    return (
      <FormEditor fields={fields}/>
    );
  }
});


React.render(<App/>, document.body);

http://jsbin.com/fabonujenu/8/edit

Edit: Instead of passing FieldEditor elements as children to FormEditor I Just pass a list of fieldIds and create them in the FormEditor instead. This makes it easier to dynamically add FieldEditors and makes the render method of FormEditor less wonkey.

Comments