I am new to react and trying to build a simple ToDo app based off of the react-starter-kit. I am using ES6 classes and unable to find a way to update parent state from a child component.
Here is the code:
import React, { PropTypes, Component } from 'react';
import withStyles from '../../decorators/withStyles';
import styles from './ToDoPage.less';
@withStyles(styles)
class ToDoPage extends Component {
static contextTypes = {
onSetTitle: PropTypes.func.isRequired
};
constructor() {
super();
this.state = {
items: ['Item1', 'Item2'],
value: ''
};
}
updateValue(newValue) {
//this.state is null here
this.setState({
value: newValue
});
}
clickHandler() {
console.log('AddToDo state:', this.state)
if (this.state.value && this.state.items) { //this.state is null here
this.setState({
items: this.state.items.push(this.state.value)
});
}
}
render() {
let title = 'To Do List';
this.context.onSetTitle(title);
return (
<div className="ToDoPage">
<div className="ToDoPage-container">
<h1>{title}</h1>
<AddToDoTextBox handleUpdate={this.updateValue}/>
<AddToDoButton handleClick={this.clickHandler}/>
<div className = "todo-items">
<br/>
<div>({this.state.items.length}) items found.</div>
<ToDoList items = {this.state.items}/>
</div>
</div>
</div>
);
};
}
class ToDoList extends Component {
static propTypes = {
items: PropTypes.array.isRequired
};
render() {
console.log(this.props.items);
return (
<ul>
{this.props.items.map(function(item) {
return <li key={item}>{item}</li>
}) }
</ul>);
};
};
class AddToDoButton extends Component {
static propTypes: {
clickHandler: React.PropTypes.func
}
constructor() {
super();
}
render() {
return (<button
className="btn btn-primary"
onClick={this.props.handleClick.bind(this)}>Add ToDo</button>);
};
}
class AddToDoTextBox extends Component {
static propTypes: {
handleUpdate: React.PropTypes.func
}
constructor() {
super();
this.state = {
value: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({value: e.target.value});
this.props.handleUpdate.call(this, e.target.value);
}
render() {
return <input type="text" placeholder="Enter todo item here" size="50" onChange={this.handleChange}/>
};
}
export default ToDoPage;
I want to access ToDoPage's state from updateValue() and clickHandler() functions but this.state is null as I binding to the child components they are being called from (i.e AddToDoButton and AddToDoTextBox). How can I access/update ToDoPage's state from clickHandler() or updateValue()?
Update Parent and Child Components State in React.js May 08, 2020 When you nest your components in react.js, in some cases, you may want to update the state of the parent component from the child component or vice versa. To achieve this sort of communication you can simply use props and references.
So, based on selectio, data on child component must change. The solution is to maintain state in parent component, and pass the props to child component. And the child component, will read data from props. Now the child component will just render data from its props. Hope it helps.
— React Context provides a way to pass data through the component tree without having to pass props down manually at every level ☘️ In any application, data is essential. We all know this, in React, state and props are two very important properties and are commonly used, easily explained: they are all used to save the state of the data.
Let’s take a look at the the code snippet that handles React state update and returns the new state object to the parent component. In the handleChange () method, I’m calling this.setState (), and updating the component state object with the new values.
When you want to do change from Child to Parent you need to pass a function to the Child as prop. Something like (example with some ES7 syntax):
Parent component
import React, { Component } from 'react'
export default class Parent extends Component {
constructor() {
super();
this.handleChange = this.handleChange.bind(this);
this.state = {
number: 1
};
}
handleChange(num) {
this.setState({
number: num
});
}
render() {
return (
<Child changeNumber={this.handleChange} />
);
}
}
Child component
import React, { PropTypes, Component } from 'react'
export default class Child extends Component {
static propTypes = {
changeNumber: PropTypes.func
}
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
this.props.changeNumber(e.target.value);
}
render() {
return (
<button onClick={this.handleClick}> 3 </button>
);
}
}
You need to use .bind(this)
at your handleUpdate
and handleClick
assignments in ToDoPage.render()
:
<AddToDoTextBox handleUpdate={this.updateValue.bind(this)}/>
<AddToDoButton handleClick={this.clickHandler.bind(this)}/>
or use arrow functions
See https://facebook.github.io/react/docs/reusable-components.html#no-autobinding
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With