brandonhilkert brandonhilkert - 2 months ago 17
React JSX Question

React refs with components

I have React form that has a Component used to render a drop down because the options are coming from an API. However, I can't access the ref for the embedded component. I'm putting together my first form and trying to understand the best way to approach this.

var ActivityForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();

var noteCategoryId = this.refs.note_category_id.getDOMNode().value.trim();
var content = this.refs.content.getDOMNode().value.trim();

if (!category || !content) {
return;
}

// this.props.onCommentSubmit({author: author, text: text});

this.refs.note_category_id.getDOMNode().value = '';
this.refs.content.getDOMNode().value = '';
return;
},
render: function() {
return (
<div className="new-activity">
<h3>New Activity</h3>
<form onSubmit={this.handleSubmit}>
<textarea ref='content' />
<br />

<label>Category</label>
<ActivityFormCategoryDropdown /> # THE REF IN THIS COMPONENT ISN'T ACCESSIBLE
<br />

<input type="submit" value="Add Activity" />
</form>
</div>
);
}
});

Answer

It is preferred to treat the ref as a callback attribute and no longer depend on the refs Object. If you do use the refs Object, avoid accessing refs of descendant components. You should treat refs as a private accessor and not part of a component's API. Treat only the methods exposed on a component instance as its public API.

For this case, I suggest grabbing the form from the submit event and traversing its child form elements as needed. Add name attributes since that's how form elements are identified in standard form submissions, and then you shouldn't need refs at all:

var ActivityForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();

    var form = e.target;
    var content = form.querySelector('[name="content"]').value;

    // do more things with other named form elements
  },
  render: function() {
    return (
      <div className="new-activity">
        <h3>New Activity</h3>
        <form onSubmit={this.handleSubmit}>
          <textarea name='content' />
          <br />

          <label>Category</label>
          <ActivityFormCategoryDropdown />
          <br />

          <input type="submit" value="Add Activity" />
        </form>
      </div>
    );
  }
});

Update 2016-09-21: Revise suggestion to avoid the refs Object all together per guidance from the ref String Attribute docs.

Comments