Reputation: 3182
I'm working on a project using React where I need to update the state
of the Parent Component with the Child Component's input. I did console.log()
my way through each function in the chain and found that the fetchText()
function in my parent component didn't receive the text
Here's what my parent component looks like
class AppComponent extends React.Component{
constructor(props){
super(props);
this.state = { markdownText: `` };
this.fetchText = this.fetchText.bind(this);
}
fetchText(text){
this.setState({ markdownText: text });
console.log(text);
}
render(){
return(
<div id="app-grid">
<h1>Markdown Viewer</h1>
<MarkDownComponent userInput={this.fetchText} />
<PreviewComponent />
</div>
);
}
}
My Child Component looks like this
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
this.getInput = this.getInput.bind(this);
this.sendInput = this.sendInput.bind(this);
}
getInput(event){
this.setState({ text: event.target.value });
this.sendInput();
}
sendInput(){
this.props.userInput = this.state.text;
//console.log(this.props.userInput);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
When console.log()
ing this.props.userInput
in the Child Component I get the value back as I type. So that indicates the value is making it to the property, but why isn't it updating in the parent component?
Upvotes: 0
Views: 160
Reputation: 17608
As told in the comments, there is no need to assign a state to your function. Also, if your desire is to change the text with a Child and nothing more you don't need a state in your Child. Don't use state if it is not necessary.
class AppComponent extends React.Component {
constructor(props) {
super(props);
this.state = { markdownText: "" };
this.fetchText = this.fetchText.bind(this);
}
fetchText(e) {
this.setState({ markdownText: e.target.value});
}
render() {
return (
<div id="app-grid">
<h1>Markdown Viewer</h1>
Value is now: {this.state.markdownText}
<MarkDownComponent userInput={this.fetchText} />
</div>
);
}
}
const MarkDownComponent = ( props ) => {
return (
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={props.userInput}></textarea>
</div>
)
}
ReactDOM.render(<AppComponent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 1748
Few things to note here:
you cannot change the value of props, it is passed to the component through it parent
this.props.userInput = this.state.text;
this won't work.
So, to make fetchData of parent get the text from textarea you should do like this
<textarea id="editor" rows="16" onChange={this.props.userInput}></textarea>
and in parent component :
fetchText(event){
console.log(event.target.value)
this.setState({ markdownText: event.target.value });
}
you don't require functions like getInput
and sendInput
to send data to the parent component.
Upvotes: 2
Reputation: 33974
The issue is you are assigning state value to a function which is not correct.
this.props.userInput = this.state.text; // this is incorrect
//Right one
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
this.getInput = this.getInput.bind(this);
this.sendInput = this.sendInput.bind(this);
}
getInput(event){
this.setState({ text: event.target.value });
this.sendInput();
}
sendInput(){
this.props.userInput(this.state.text);
//console.log(this.props.userInput);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
You can directly call this.props.userInput function in getInput function:
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
this.getInput = this.getInput.bind(this);
}
getInput(event){
this.props.userInput(event.target.value);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
ES6 way:
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
}
getInput = (event) => {
this.props.userInput(this.state.text);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
Upvotes: 2