Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete a ToDo Item onClick in React?

Tags:

reactjs

I'm doing a simple todo app with React, just to practise. How can I delete a list item, when clicking on it?

Here is my todos.js

export default class Todos extends Component {
    constructor(props) {
        super(props);
        this.state = { todos: [], text: '' };
    }

    addTodo(e) {
        e.preventDefault();
        this.setState({ todos: [ this.state.text, ...this.state.todos ] });
        this.setState({ text: ''});
    }

    updateValue(e) {
        this.setState({ text: [e.target.value]})
    }

    render() {
        return(
            <div>
                <form onSubmit = {(e) => this.addTodo(e)}>
                    <input
                        placeholder="Add Todo"
                        value={this.state.text}
                        onChange={(e) => {this.updateValue(e)}}
                    />
                    <button type="submit">Add Todo</button>
                </form>
                <TodoList todos={this.state.todos}/>
            </div>
        );
    }
}

And here is the TodoList.js, where I'm trying to remove a list item from.

import React, { Component } from 'react';
import { connect } from 'react-redux';

export default class TodoList extends Component {
    removeItem(e) {
        // splice this.props.todos??
    }
    render() {
        return(
            <ul>
                { this.props.todos.map((todo) => {
                    return <li onClick={(e) => { this.removeItem(e)}} key={todo}>{ todo }</li>
                })}
            </ul>
        );
    }
}
like image 896
userden Avatar asked Jun 29 '17 17:06

userden


People also ask

How do I remove an item from Click react?

To delete an item from list with React and JavaScript, we can use some array methods. to create the items state with useState . Then we define the deleteItem function that takes the index of the item to delete and returns a function that calls setItems with (items) => items. filter((_, i) => i !==

How do you delete an element in react?

To remove an element from a state array in React: Use the filter() method to iterate over the array. On each iteration, check if a condition is met. Set the state to the new array that the filter method returned.


2 Answers

To delete the todo items, first pass a function from parent component:

<TodoList todos={this.state.todos} removeTodo={this.removeTodo}/>

Bind this function in the constructor:

this.removeTodo = this.removeTodo.bind(this);

Define this function in parent component, it will delete that item from state variable:

removeTodo(name){
    this.setState({
        todo: this.state.todo.filter(el => el !== name)
    })
}

Then inside child component call this method to delete todo:

export default class TodoList extends Component {
    removeItem(e) {
        this.props.removeTodo(item);
    }
    render() {
        return(
            <ul>
                { this.props.todos.map((todo) => {
                    return <li onClick={() => { this.removeItem(todo)}} key={todo}>{ todo }</li>
                })}
            </ul>
        );
    }
}

Suggestion:

Don't call setState multiple time within a function if you want to set multiple state values then write it like this:

this.setState({
    a: value1,
    b: value2,
    c: value3
})

Working example:

class Todos extends React.Component {
    constructor(props) {
        super(props);
        this.state = { todos: [], text: '' };
        this.removeTodo = this.removeTodo.bind(this);
    }

    addTodo(e) {
        e.preventDefault();
        this.setState({ 
        	todos: [ this.state.text, ...this.state.todos ],
        	text: ''
        });
    }

    removeTodo(name, i){
        let todos = this.state.todos.slice();
        todos.splice(i, 1);
        this.setState({
            todos
        });
    }

    updateValue(e) {
        this.setState({ text: e.target.value})
    }

    render() {
        return(
            <div>
                <form onSubmit = {(e) => this.addTodo(e)}>
                    <input
                        placeholder="Add Todo"
                        value={this.state.text}
                        onChange={(e) => {this.updateValue(e)}}
                    />
                    <button type="submit">Add Todo</button>
                </form>
                <TodoList todos={this.state.todos} removeTodo={this.removeTodo}/>
            </div>
        );
    }
}

class TodoList extends React.Component {

    removeItem(item, i) {
        this.props.removeTodo(item, i);
    }

    render() {
        return(
            <ul>
                { this.props.todos.map((todo,i) => {
                    return <li onClick={() => { this.removeItem(todo, i)}} key={i}>{ todo }</li>
                })}
            </ul>
        );
    }
}

ReactDOM.render(<Todos/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>

Update:

This is for @whs.bsmith doubt, the code that i suggested will work properly in the case where user will add the unique items in the todo list, if he will try to add the same item it will not reflect in ui because OP is using the todo items name as the key and key should be unique.

To solve that issue:

In working snippet i used indexes in place of todo items name for key, that will work properly and it will allow the user to add same item multiple times and on deletion, it will delete only that specific item not all the item having that same name, But it's not a good idea to use indexes as the key.

like image 58
Mayank Shukla Avatar answered Sep 21 '22 18:09

Mayank Shukla


You have called setState two times in the addTodo function. You can set todos and text in a single setState function like this:

addTodo(e) {
    e.preventDefault();
    this.setState({ todos: [ this.state.text, ...this.state.todos ], text: '' });
}

Do not write removeItem function in TodoList Component as it is purely working on props. Pass a removeItem function from Todos to it and remove that item in Todos's removeItem function like this:

import React, {Component} from 'react'
export default class Todos extends Component {
  constructor(props) {
    super(props);
    this.state = { todos: [], text: '' };
    this.removeItem = this.removeItem.bind(this)
  }

  addTodo(e) {
    e.preventDefault();
    this.setState({ todos: [ this.state.text, ...this.state.todos ], text: '' });
  }


  updateValue(e) {
    this.setState({ text: [e.target.value]})
  }
  removeItem(index) {
    const todos = this.state.todos.filter((todo, todoIndex) => {
      return todoIndex !== index
    })
    this.setState({ todos })
  }
  render() {
    return(
      <div>
        <form onSubmit = {(e) => this.addTodo(e)}>
          <input
            placeholder="Add Todo"
            value={this.state.text}
            onChange={(e) => {this.updateValue(e)}}
            />
          <button type="submit">Add Todo</button>
        </form>
        <TodoList todos={this.state.todos} removeItem={this.removeItem} />
      </div>
    );
  }
}

class TodoList extends Component {
  render() {
    return(
      <ul>
        { this.props.todos.map((todo, index) => {
          return <li onClick={(e) => { this.props.removeItem(index)}} key={todo}>{ todo }</li>
        })}
      </ul>
    );
  }
}

Hope, it helps.

like image 22
Ritesh Bansal Avatar answered Sep 19 '22 18:09

Ritesh Bansal