user3673959
user3673959

Reputation:

How to remove the li element on click from the list in reactjs?

    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 using addElement function.But can't figure out how to remove the particular li element from the ul list on clicking the deleteElement function.I tried using splice() 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

Answers (3)

Oleksandr T.
Oleksandr T.

Reputation: 77522

In your code there are several mistakes

  1. don't use this.forceUpdate();, instead you should use setState

  2. 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>
  }
});

Example

Upvotes: 3

Jamie Dixon
Jamie Dixon

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

Andreyco
Andreyco

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}>&times;</span>
      </li>
    );
  }
});

Working fiddle here... https://jsfiddle.net/69z2wepo/31009/

Upvotes: 0

Related Questions