I'm having problems creating a functioning "delete button" in my react todo app

I'm brand new to Reactjs and I'm working on my first app, a todo app of course. However, everything was going smoothly until I was asked to create a delete button to remove my todos. I'm stuck and have been puzzled over this for almost 3 days. Any help or advice would be appreciated.

react-to-do/src/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: ""
    };
    this.deleteTodo = this.deleteTodo.bind(this);
  }

  deleteTodo(description) {
    this.setState({
      todos: this.state.todos.filter(
        (todos, index) => todos.description !== description
      )
    });
  }

  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;

react-to-do/src/ToDo.js

import React, { Component } from "react";

class ToDo extends Component {
  deleteToDo(description) {
    this.props.deleteToDo(description);
  }

  render() {
    return (
      <div className="wrapper">
        <button
          className="deleteToDo"
          onClick={e => this.deleteToDo(this.props.description)}
        >
          Delete
        </button>
        {this.props.deleteToDo}

        <li>
          <input
            type="checkbox"
            checked={this.props.isCompleted}
            onChange={this.props.toggleComplete}
          />
          <span>{this.props.description}</span>
        </li>
      </div>
    );
  }
}

export default ToDo;

react-to-do/src/index.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";

ReactDOM.render(<App />, document.getElementById("root"));
registerServiceWorker();

2 answers

  • answered 2018-02-13 01:10 Shanon Jackson

    You never pass your "deleteTodo" function as a prop to your "toDo" component. change the portion where you create you're todo components in that map to resemble something like this...

    map.... => <toDo deleteToDo={this.deleteTodo}......... />
    

    remember components are scoped to themselves if you want to call a function that exists in the parents context in a child, a reference of that function must be passed to that child as a prop.

  • answered 2018-02-13 01:10 Prakash Kandel

    Your code should look like

    class ToDo extends React.Component {
            deleteToDo(description) {
              this.props.deleteToDo(description);
            }
              render() {
                return (
                  <div className="wrapper">
    
                  <button className="deleteToDo" onClick = {(e) => 
                      this.deleteToDo(this.props.description)}>Delete</button> 
                      {() => this.props.deleteToDo(this.props.description)}
    
                  <li>
                    <input type="checkbox" checked={ this.props.isCompleted } 
            onChange={ this.props.toggleComplete } />
                    <span>{ this.props.description }</span>
                  </li>
                  </div>
                );
              }
            }
    
        class App extends React.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: ''
                };
                  this.deleteTodo = this.deleteTodo.bind(this);
              }
              deleteTodo(description) {
              const filteredTodos = this.state.todos.filter((todo, index) =>  todo.description !== description);
                this.setState({
                  todos: filteredTodos
                });
              }
    
              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>
                );
              }
            }
    

    Here you forgot to pass props from App and description parameter from ToDo component.

    Try here https://jsfiddle.net/prakashk/69z2wepo/101369/#&togetherjs=B3l5GDzo8A