I have a React component with a <textarea>
in it. I want this <textarea>
to have all of the following characteristics:
- editable, e.g. must use
defaultValue
OR (value
WITHonChange
) - initial content determined by incoming prop
- content automatically changes when incoming props change
If I use defaultValue
, then the <textarea>
will not update when the component updates due to modified props from the parent.
If I use the value
with onChange
model as described in the React docs and in this SO answer, I fall into a trap and can't use incoming props from the parent to modify the state of the <textarea>
because:
- the
<textarea>
'svalue
must point to its component's state - component state can only be set by incoming props in
getInitialState
;setState
can't be used incomponentDidUpdate
, for example; so I can never update state, and thus thevalue
of my<textarea>
, on a re-render
So my question is, how can I have a <textarea>
in ReactJS whose value
can be updated by the user, by incoming props on initial load, and also by updates to incoming props?
The only nasty workaround I've thought of so far is to use a "non-managed" state, my own JSON props tacked onto the component in place of formal React state. But this is not "the React way."
Simplified code follows in case it helps.
This code works on initial component load, but never uses props again so can't update the <textarea>
content from props.
var Input = React.createClass({
componentDidUpdate: function() {
// when component updates, can't use setState here to update state,
// and thus can't update <textarea> content
},
getInitialState: function() {
return {
draftPath: this.props.draftPath,
draftBody: this.props.draftBody
};
},
handlePathChange: function(event) {
this.setState({
draftPath: event.target.value
});
},
handleBodyChange: function(event) {
this.setState({
draftBody: event.target.value
});
},
render: function() {
return (
<div id='cyoag-input-container'>
<textarea id='cyoag-input-path' type='text'
value={this.state.draftPath} onChange={this.handlePathChange} >
</textarea>
<textarea id='cyoag-input-body' type='text'
value={this.state.draftPath} onChange={this.handleBodyChange} >
</textarea>
</div>
);
}
}