Home » Reactjs » How to access child's state in React?

How to access child's state in React?

Posted by: admin November 29, 2017 Leave a comment

Questions:

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?

Answers:

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.

Questions:
Answers:

If you want to access the state of a component’s children, you can assign a property called ref to each child. This property takes a callback function that is passed a reference to the attached component. This callback is executed immediately after the component is mounted or unmounted.

For example:

ES5:

<FieldEditor
    ref={function(fieldEditor1){this.fieldEditor1 = fieldEditor1;}}
    {...props}
/>

ES6:

<FieldEditor
    ref={(fieldEditor1) => {this.fieldEditor1 = fieldEditor1;}
    {...props}
/>

In these examples the reference is stored on the parent component. To call this component in your code, you can use:

this.fieldEditor1

and then use this.fieldEditor1.state to get the state.

One thing to note, make sure your child component has rendered before you try to access it ^_^

If you want to read more about React’s ref property, check out this page from Facebook.

Make sure you read the “Don’t Overuse Refs” section that says that you shouldn’t use the child’s state to “make things happen”.

Hope this helps ^_^

Edit: Changed answer to use callback refs as opposed to string refs as string refs are likely to be removed in a future React.js release (see Refs and the DOM for more details).