问题
I'm trying to write a note taking/organizing app and I've run into a frustrating bug.
Here's my component:
import React from 'react';
const Note = (props) => {
let textarea, noteForm;
if (props.note) {
return (
<div>
<button onClick={() => {
props.handleUpdateClick(props.selectedFolderId, props.selectedNoteId, textarea.value);
}}>
Update
</button>
<textarea
defaultValue={props.note.body}
ref={node => {textarea = node;}}
/>
</div>
);
} else {
return <div></div>;
}
};
export default Note;
As it currently stands, whenever I switch between notes and rerender the note component with new content from the note.body prop, the textarea does not change and retains the content from the previous note. I've tried using the value attribute instead of the defaultValue attribute for the text area which doe fix the problem of the text area content not changing when the component rerenders, but when I do that I'm longer able to type in the textarea field to update the note
Doe anyone know a way I can both allow for users to type in the text field to update the note as well as have the textarea content change when I render different notes?
Thank you
回答1:
The problem is that setting the value to your prop will cause all re-renders of the component to use the same prop, so new text is obliterated. One solution is to preserve the text in the local state of the component. To simultaneously listen to prop changes, you can set the state when you receive new props.
const Note = React.createClass({
getInitialState() {
return {
text : this.props.note.body
}
},
componentWillReceiveProps: function(nextProps) {
if (typeof nextProps.note != 'undefined') {
this.setState({text: nextProps.note.body });
}
},
render() {
if (this.props.note) {
return (
<div>
<button onClick={(e) => {
// Fire a callback that re-renders the parent.
// render(this.textarea.value);
}}>
Update
</button>
<textarea
onChange={e => this.setState({ text : e.target.value })}
value={this.state.text}
ref={node => {this.textarea = node;}}
/>
</div>
);
} else {
return <div></div>;
}
}
});
https://jsfiddle.net/69z2wepo/96238/
If you are using redux, you could also fire an action on the change event of the input to trigger a re-render. You could preserve the input value in a reducer.
回答2:
Because componentWillReceiveProps
is now unsafe Max Sindwani's answer is now a little out date.
Try these steps:
- convert your component to a class
- now you can include the
shouldComponentUpdate()
lifecycle hook - create your event handler and pass it into onChange
in
<textarea>
you can swap outdefaultValue
attribute forvalue
(just use event.preventDefault() in the handler so that a user can continue to update text if required)import React from 'react'; export class Note extends React.Component { constructor(props) { super(props); this.state={text: this.props.note.body} } shouldComponentUpdate(nextProps) { if(nextProps.note.body !== this.state.text) { this.setState({text: nextProps.note.body}) return true; } return false; } updateText = (event) => { event.preventDefault(); this.setState({text: nextProps.note.body}); } render() { if (this.props.note) { return ( <div> <textarea onChange={this.updateText} value={this.state.text} name={'display'} /> </div> ); } else { return <div></div>; } }});
来源:https://stackoverflow.com/questions/41775004/reactjs-component-textarea-not-updating-on-state-change