Reputation: 2285
So I've read that we should try avoiding refs when accessing Child components
(https://facebook.github.io/react/docs/more-about-refs.html)
In my case, however, I couldn't think of a way to avoid this in my situation..
Scenario:
I have a MyForm parent component which contains a TagInput child component, which resembles Stackoveflow's "Tags" input field. As the user types an input+SPACE, a tag is added to TagInput's internal state. When the user submits the form, the selected tag list is posted to my server.
Implementation:
var MyForm = React.createClass({
submit: function() {
var selectedTags = this.refs.tagInput.state.selectedTags;
$.post(
SERVER_URL,
data: { tags: selectedTags }
);
},
render: function() {
return (
<form onSubmit={this.submit}>
<TagInput ref="tagInput">
</form>
);
}
});
var TagInput = React.createClass({
getInitialState: function() {
return {
selectedTags: []
}
},
// This is called when the user types SPACE in input field
handleAddTag: function(tag) {
this.setState({
selectedTags: this.state.selectedTags.concat(tag);
});
},
render: function() {
return (
<form>
<ul>{this.state.selectedTags}</ul>
<input type="text" />
</form>
);
}
});
The above code works fine and does what is expected. The only concern is I'm using refs to directly access the Child component's internal state, and I'm not sure if this is the right "React" way.
I guess one option is to maintain the "selectedTags" state in MyForm instead of TagInput. This doesn't really make sense in my case, because in reality my form contains 5 TagInput components and many other states to manage..
Can anyone think of a way to improve my design? Or is using refs unavoidable in my case?
Thanks
Upvotes: 0
Views: 2038
Reputation: 251
You can pass handleAddTag from the parent component into the child and keep the state of the selected tags in the form component. Now when you submit the form you are pulling from the state on the form rather than using refs.
var MyForm = React.createClass({
getInitialState: function() {
return {
selectedTags: []
}
},
submit: function() {
var selectedTags = this.state.selectedTags;
$.post(
SERVER_URL,
data: { tags: selectedTags }
);
},
// This is called when the user types SPACE in input field
handleAddTag: function(tag) {
this.setState({
selectedTags: this.state.selectedTags.concat(tag);
});
},
render: function() {
return (
<form onSubmit={this.submit}>
<TagInput handleAddTag={this.handleAddTag} ref="tagInput">
</form>
);
}
});
//Use this.props.handleAddTag() to update state in Form Component
var TagInput = React.createClass({
render: function() {
return (
<form>
<ul>{this.state.selectedTags}</ul>
<input type="text" />
</form>
);
}
});
I found that using refs to get some piece of data is not as bad as using refs to modify the UI which is very bad as it will cause the UI to not be inline with your state or your application.
Upvotes: 2