Reputation: 2333
I have an issue I can't seem to crack even after checking out a few other posts on here and trying a few things out. I am playing around with React and making a quick todo list. Easy enough as I can add new names and display them on the page as intended. I want to be able to delete items that I choose and for that I was looking around and saw others doing something like this to delete items:
deleteName(id, e) {
const { names } = this.state;
this.setState({
names: names.filter(name => name.id !== id)
});
}
That made sense to me but I wasn't adding any id's to my <li>
items so I thought I could just do:
this.setState({
names: names.filter(name => name !== name)
});
But this will just delete the whole list. What am I doing wrong? Should I restructure how I add names to the array to have an id and check that? I'll post the full component code below. Any help I can get is always appreciated. Thanks guys.
class ContactListPage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
names: []
};
this.addName = this.addName.bind(this);
this.deleteName = this.deleteName.bind(this);
}
addName(name) {
const { names } = this.state;
if (name === '') {
console.log('add a name first!')
} else {
this.setState({
names: names.concat(name)
});
}
}
deleteName(id, e) {
const { names } = this.state;
this.setState({
names: names.filter(name => name !== name)
});
}
render() {
const { names } = this.state;
const named = names.map((name, i) => (
<Card key={i} className='todo-list'>
<CardText>
<li>{name}
<FloatingActionButton className='fab-delete' mini onClick={this.deleteName}>
<i className="material-icons fab-icon-delete" style={{color: 'white'}}>-</i>
</FloatingActionButton>
</li>
</CardText>
</Card>
));
return (
<div className='contact-list'>
<div className="field-line">
<NewName addName={this.addName} />
<ul className='new-name'>
{named}
</ul>
</div>
</div>
);
}
}
Upvotes: 2
Views: 2381
Reputation: 17398
It's hard to tell, but are you referencing name
when the passed argument to your callback is actually called id
?
Try this:
deleteName(name) {
this.setState((prevState) => ({
names: prevState.names.filter(_name => name !== _name);
}));
}
And change the following:
onClick={this.deleteName.bind(null, name)}
Upvotes: 2
Reputation: 1214
You're comparing each name with itself, that will yield an empty list regardless of what's in it (except I guess NaN?).
names.filter(name => name !== name)
I think you want to pass the name into your delete function from the view. It's been a while since I've done React, but you could probably do this with a lambda in the JSX.
deleteName(nameToDelete) {
const { names } = this.state;
this.setState({
names: names.filter(name => name !== nameToDelete)
});
}
render() {
// Simplified to focus on the onClick change
return names.map(name => <Card>
...
<FloatingActionButton onClick={(e) => this.deleteName(name)} ... />
...
</Card>);
}
If you need to worry about duplicate names, then you can pass the current index into deleteName()
rather than the string itself. Up to you if that's necessary or not.
Upvotes: 3
Reputation: 2339
In the callback for the filter, name !== name
will always be false since an object is identical to itself. i.e name === name
. Therefore the expression names.filter(name => name !== name)
will return an empty array and erase your results. You can change your onClick
handler to something like this to pass in your id: onClick={(e) => this.deleteName(i, e)}
and then use names.filter((name, i) => i !== id)
to 'delete' the name, although I imagine you would would probably want to make a copy of the names array and then splice the corresponding name out of it.
Upvotes: 0