Reputation:
var ListItem = require('./listItem');
var App = React.createClass({
getInitialState : function(){
return{
items : []
}
},
deleteElement: function(){
},
addElement : function(){
this.state.items.push(<ListItem />);
this.forceUpdate();
},
render : function(){
return (
<div>
<ul>{this.state.items.map(function(item,i){return (
<li>
<p onClick='this.deleteElement'>(-)</p>
{item}
</li>
)})}</ul>
<p onClick='this.addElement'>(+)</p>
</div>
);
}
});
Currently I can add
li
elements to the array usingaddElement function
.But can't figure out how to remove the particularli
element from theul
list on clicking thedeleteElement function
.I tried usingsplice()
but didn't work.I am new to reactjs.So don't know how to remove the li elements on click in the react way.
Upvotes: 3
Views: 8029
Reputation: 77522
In your code there are several mistakes
don't use this.forceUpdate();
, instead you should use setState
to onClick
you should pass reference to function not string 'this.addElement'
Now consider how you can delete elemet from list., you need pass to deleteElement
index this.deleteElement.bind(this, i)
and remove element by index from items
array, and then set new state
var App = React.createClass({
getInitialState : function(){
return {
items : []
}
},
deleteElement: function(index) {
this.setState({
items: this.state.items.filter(function (e, i) {
return i !== index;
})
});
},
addElement: function() {
this.setState({
items: this.state.items.concat(<ListItem time={ +new Date() } />)
});
},
render: function() {
var list = this.state.items.map(function(item, i) {
return <li key={ i }>
<p onClick={ this.deleteElement.bind(this, i) }>(-)</p>
<span>{ item }</span>
</li>
}, this);
return <div>
<ul>{ list }</ul>
<p onClick={ this.addElement }>(+)</p>
</div>
}
});
Upvotes: 3
Reputation: 54021
In your map, when setting up the deleteElement callback, pass in the index of the current item.
<p onClick={ function () { this.deleteElement(i) } }>(-)</p>
Then you can build a new array by slicing it and excluding the current index.
deleteElement: function(index){
var items = this.state.items;
var leftSide = items.slice(0, index);
var rightSide = items.slice(index + 1, items.length);
this.setState({ items: leftSide.concat(rightSide) });
}
slice
is preferred to splice
because slice
will not mutate an existing array. Here we build a new array and avoid any mutations.
If you're using ES6 this can be reduced slightly:
<p onClick={() => this.deleteElement(i) }>(-)</p>
deleteElement: (index) => {
var items = this.state.items;
var leftSide = items.slice(0, index);
var rightSide = items.slice(index + 1, items.length);
this.setState({ items: [...leftSide, ...rightSide] });
}
Once downside to be aware of when doing this, the function surrounding deleteElement
in your JSX will be re-created on every render
. This creates more work for the garbage collector because there will be a bunch of unused function pointers in memory.
Upvotes: 0
Reputation: 22872
Here is what would I do...
remove(idx) {
return (event) => {
// Concatening original items array returns new array - this is important!
const items = this.state.items.concat();
items.splice(idx, 1);
this.setState({ items });
}
},
render() {
return (
<div>
...
<ul>
{ this.state.items.map((item, i) => <Item key={i} remove={this.remove(i)} text={item} />) }
</ul>
...
</div>
);
}
Here, you are passing index of item you would like to remove. Of course, calling function would be no good in render - it would remove all items on render (actually, you should not change state in render method). Instead, you return function that will be executed on click.
Item component could look similar to this:
const Item = React.createClass({
render() {
return (
<li>
{ this.props.text }
<span onClick={this.props.remove}>×</span>
</li>
);
}
});
Working fiddle here... https://jsfiddle.net/69z2wepo/31009/
Upvotes: 0