Reputation: 165
I try to pass state to the child, to update the list of objects.
When I add an entry, it's not rendered in the child component.
I also checked that state.contacts
actually gets replaced with new array, but it didn't work.
constructor(props) {
this.super(props);
}
removeContact(event) {
this.setState((state) => {
state.contacts = state.contacts.filter((contact) => contact.key !== event.target.key )
return state;
})
}
render() {
return (
<Fragment>
<span>{this.props.contact.name}</span>
<span>{this.props.contact.phone}</span>
<span>{this.props.contact.adress}</span>
<a href="#" onClick={this.removeContact}>X</a>
</Fragment>
)
}
}
class Contacts extends Component {
constructor(props) {
super(props);
this.state = { contacts: props.contacts };
}
render() {
console.log(this.state.contacts); // always displays empty array
return (
<div>
{this.state.contacts.map((contact, index) =>
<div>
<Contact key={index} contact={contact} contacts={this.state.contacts}/>
</div>
)}
</div>
)
}
}
class App extends Component {
state = {
time: new Date(),
name: "",
phone: "",
adress: "",
contacts: []
}
change = (event) => {
let nameOfField = event.target.name;
this.setState({[nameOfField]: event.target.value})
}
// click = () => {
// this.setState((state) => {
// state.time = new Date();
// return state;
// })
// }
addContact = () => {
let name = this.state.name;
let phone = this.state.phone;
let adress = this.state.adress;
this.setState((state) => {
return {contacts: [ ... state.contacts.concat([{name, adress, phone}])]}
});
}
render() {
return (
<div className="App">
<Timestamp time={this.state.time}/>
<Contacts contacts={this.state.contacts}/>
<input name="name" value={this.state.name} onChange={this.change} placeholder="Name"/>
<input name="phone" value={this.state.phone} onChange={this.change} placeholder="Phone"/>
<input name="adress" value={this.state.adress} onChange={this.change} placeholder="Adress"/>
<button onClick={this.addContact}>Add contact</button>
</div>
)
}
}
ReactDOM.render(<App time={Date.now().toString()}/>, document.getElementById('root'));
Upvotes: 1
Views: 63
Reputation: 2853
You are currently modifying the state in Contacts
from it's child component Contact
. You can't update a parents state directly from within a child component.
What you could do is create a removeContact
function in your Contacts
component and pass the entire function down to your Contact
component. That way when you call removeContact
in your child component, it will actually call it from the parent, modify the parents state, and update all it's children with the new state.
Upvotes: 2
Reputation: 67336
If values are passed to Components you should render them as props
. There is no need to copy into the child component state:
class Contacts extends Component {
render() {
console.log(this.props.contacts); // use props instead of state
return (
<div>
{this.props.contacts.map((contact, index) =>
<div>
<Contact key={index} contact={contact} contacts={this.props.contacts}/>
</div>
)}
</div>
)
}
}
Using this.props
is good practice because it allows React to deterministically render (If the same props are passed, the same render result is returned).
Upvotes: 2