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\
Composite components can have their own refs; you can reach in to them to access the refs further down the component hierarchy.
Example:
<script src="http://fb.me/react-with-addons-0.11.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.11.2.js"></script>
<div id="app"></div>
<script type="text/jsx">
/** @jsx React.DOM */
var Parent = React.createClass({
render: function() {
return (
<div>
<Child ref="child" />
<div><button onClick={this.handleClick}>Alert Text</button></div>
</div>
);
},
handleClick: function() {
alert(this.refs.child.refs.textarea.getDOMNode().value);
}
});
var Child = React.createClass({
render: function() {
return <textarea ref="textarea" />;
}
});
React.renderComponent(<Parent />, document.getElementById("app"));
</script>
However, ssorallen is correct—you should try to avoid this if possible. Instead, you should either pass callbacks into children:
<script src="http://fb.me/react-with-addons-0.11.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.11.2.js"></script>
<div id="app"></div>
<script type="text/jsx">
/** @jsx React.DOM */
var Parent = React.createClass({
getInitialState: function() {
return { text: "" };
},
render: function() {
return (
<div>
<Child onChange={this.updateText} />
<div><button onClick={this.handleClick}>Alert Text</button></div>
</div>
);
},
handleClick: function() {
alert(this.state.text);
},
updateText: function(text) {
this.setState({text: text});
}
});
var Child = React.createClass({
render: function() {
return <textarea onChange={this.handleChange} />;
},
handleChange: function(evt) {
this.props.onChange(evt.target.value);
}
});
React.renderComponent(<Parent />, document.getElementById("app"));
</script>
or expose a public API in the child:
<script src="http://fb.me/react-with-addons-0.11.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.11.2.js"></script>
<div id="app"></div>
<script type="text/jsx">
/** @jsx React.DOM */
var Parent = React.createClass({
render: function() {
return (
<div>
<Child ref="child" />
<div><button onClick={this.handleClick}>Alert Text</button></div>
</div>
);
},
handleClick: function() {
alert(this.refs.child.getText());
}
});
var Child = React.createClass({
render: function() {
return <textarea />;
},
getText: function() {
return this.getDOMNode().value;
}
});
React.renderComponent(<Parent />, document.getElementById("app"));
</script>
or use some other data flow management (e.g. flux, events, etc).
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;
// Use the standard [`HTMLFormElement.elements`][1] collection
//
// [1]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
var content = form.elements['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.