1

I want to add a delete button to my 'Todo' component

also make a method called deleteTodo in my 'App' component

pass the deleteTodo method to the 'ToDo' component as a prop

and finally add an onClick event listener to the delete button

I've been stuck for days trying to figure this out any help would be much appreciated

my Todo.js component

import React, { Component } from 'react';

class ToDo extends Component {
 render() {
      return (
          <li>
            <input type="checkbox" checked={ this.props.isCompleted } onChange={ this.props.toggleComplete } />
            <span>{ this.props.description }</span>
            <button> </button>
            </li>
      );
    }
}

export default ToDo;



the App

import React, { Component } from 'react';
import './App.css';
import ToDo from './components/ToDo.js';

class App extends Component {
  constructor(props) {
      super(props);
      this.state = {
        todos: [
          { description: 'Walk the cat', isCompleted: true },
          { description: 'Throw the dishes away', isCompleted: false },
          { description: 'Buy new dishes', isCompleted: false }
        ],
          newTodoDescription: ''
      };
   }

  deleteTodo() {}

  handleChange(e) {
      this.setState({ newTodoDescription: e.target.value })
    }

  handleSubmit(e) {
      e.preventDefault();
      if (!this.state.newTodoDescription) { return }
      const newTodo = { description: this.state.newTodoDescription, isCompleted: false };
      this.setState({ todos: [...this.state.todos, newTodo], newTodoDescription: '' });   
    }

  toggleComplete(index) {
      const todos = this.state.todos.slice();
      const todo = todos[index];
      todo.isCompleted = todo.isCompleted ? false : true;
      this.setState({ todos: todos });
    }

  render() {
    return (
      <div className="App">
        <ul>
        { this.state.todos.map( (todo, index) => 
                    <ToDo key={ index } description={ todo.description } isCompleted={ todo.isCompleted } toggleComplete={ () => this.toggleComplete(index) } />
                  )}
        </ul> 
        <form onSubmit={ (e) => this.handleSubmit(e) }>
                <input type="text" value={ this.state.newTodoDescription } onChange={ (e) => this.handleChange(e) } />
                <input type="submit" />
              </form>
      </div>
    );
  }
}

export default App;


Dalton
  • 127
  • 1
  • 2
  • 7

2 Answers2

1

Define your deleteToDo method in app component and pass it down to ToDo component as follows.

<ToDo 
   key={ index } 
   description={ todo.description } 
   isCompleted={ todo.isCompleted } 
   toggleComplete={ () => this.toggleComplete(index) } 
   deleteToDo={this.deleteToDo}
/>

Then inside your ToDo component you can add the handler as

<button onClick={this.props.deleteToDo}> </button>

Hope this solves your query!!

Jayavel
  • 3,377
  • 2
  • 21
  • 35
JupiterAmy
  • 374
  • 2
  • 11
1
  1. Change all your event handler functions to arrow functions or bind them manually in constructor otherwise you can’t do setState or access to props inside these functions
  2. You already have deleteTodo function declared in App.js Component so pass down this function as prop to Todo component.
  3. Call deleteTodo function on button onClick using this.props.deleteTodo by passing description as parameter. You will use this description to remove todo from todos list in deleteTodo function
  4. Now, when button is clicked you need to delete an item so do filter on todos state array with description
  5. And set the newly returned todos to your state so that you will see only available todos

Here is updated code

App.js

 import React, { Component } from 'react';
 import './App.css';
 import ToDo from './components/ToDo.js';

 class App extends Component {
      constructor(props) {
          super(props);
          this.state = {
              todos: [
                   { description: 'Walk the cat', isCompleted: true },
                   { description: 'Throw the dishes away', isCompleted: false },
                   { description: 'Buy new dishes', isCompleted: false }
               ],
               newTodoDescription: ''
           };
        }

    deleteTodo = description  => {
          const newTodos = this.state.todos.filter(todo => todo.description != description);
          this.setState({
                 todos: newTodos
           });
    }

    handleChange = e => {
         this.setState({ newTodoDescription: e.target.value })
     }

    handleSubmit = e => {
         e.preventDefault();
         if (!this.state.newTodoDescription) { return }
         const newTodo = { description: this.state.newTodoDescription, isCompleted: false };
          this.setState({ todos: [...this.state.todos, newTodo], newTodoDescription: '' });   
     }

     toggleComplete = index => {
          const todos = this.state.todos.slice();
          const todo = todos[index];
          todo.isCompleted = todo.isCompleted ? false : true;
          this.setState({ todos: todos });
      }

      render() {
          return (
             <div className="App">
                 <ul>
                     { this.state.todos.map( (todo, index) => 
                            <ToDo key={ index } description={ todo.description } isCompleted={ todo.isCompleted } toggleComplete={ () => this.toggleComplete(index) } deleteTodo={this.deleteTodo} />
                        )}
                 </ul> 
                <form onSubmit={ (e) => this.handleSubmit(e) }>
                      <input type="text" value={ this.state.newTodoDescription } onChange={ (e) => this.handleChange(e) } />
                     <input type="submit" />
                 </form>
            </div>
          );
         }
       }

       export default App;

Todo.js

    import React, { Component } from 'react';

     class ToDo extends Component {
         render() {
              return (
                   <li>
                       <input type="checkbox" checked={ this.props.isCompleted } onChange={ this.props.toggleComplete } />
                      <span>{ this.props.description }</span>
                      <button onClick={() => this.props.deleteTodo(this.props.description)}>Delete Todo </button>
                   </li>
             );
          }
        }

      export default ToDo;
Hemadri Dasari
  • 32,666
  • 37
  • 119
  • 162
  • In the future should i stick to using arrow functions when working with react to make sure data flows properly? – Dalton Feb 13 '19 at 05:53
  • @Dalton It’s up to your coding style. Please refer this thread for more details about when to use arrow function and when to use regular function https://stackoverflow.com/questions/52031147/react-which-is-recommended-arrow-or-normal-function – Hemadri Dasari Feb 13 '19 at 05:59