Home > Net >  How to delete a list item with React (function component)
How to delete a list item with React (function component)

Time:10-26

Just working on a simple to do list for practice and I would like to be able to click on an item on my list to remove it. I think I have it very close but cannot figure out how to get some sort of data from the clicked li to compare it against my array.

App.js

import { useState } from "react";
import "./App.css";
import Newtodo from "./NewTodo/NewTodo";
import TodoList from "./TodoList/TodoList";

let INITIAL_TODOS = [
  { id: "e1", title: "Set up meeting", date: new Date(2021, 0, 14), index: 0 },
  {
    id: "e2",
    title: "Doctor appointment",
    date: new Date(2021, 2, 14),
    index: 1,
  },
  { id: "e3", title: "Work on project", date: new Date(2021, 1, 22), index: 2 },
  { id: "e4", title: "Update resume", date: new Date(2021, 6, 14), index: 3 },
];

const App = () => {
  const [todos, setTodos] = useState(INITIAL_TODOS);

  const deleteItem = (e) => {
    const newTodos = todos.filter((item) => item.index !== 1 /*This works properly with a hardcoded value(1) but how can this be done dynamically as e doesn't seem to have anything useful within it (like e.target.value)*/);
    setTodos(newTodos);
  };

  return (
    <div className="App">
      <Newtodo />
      <TodoList items={todos} handleDelete={deleteItem} />
    </div>
  );
};

export default App;

TodoList.js

import "./TodoList.css";
import Todo from "./Todo";

const TodoList = (props) => {
  return (
    <div className="todo-list">
      <ul>
        {props.items.map((todo, i) => (
          <Todo
            index={i}
            key={todo.id}
            title={todo.title}
            date={todo.date}
            handleDelete={props.handleDelete}
          />
        ))}
      </ul>
    </div>
  );
};

export default TodoList;

Todo.js

import "./Todo.css";

const Todo = (props) => {
  const month = props.date.toLocaleString("en-US", { month: "long" });
  const day = props.date.toLocaleString("en-US", { day: "2-digit" });
  const year = props.date.getFullYear();

  return (
    <li onClick={props.handleDelete} className="todo-item">
      <h2>{props.title}</h2>
      <span>
        {day}, {month}, {year}
      </span>
    </li>
  );
};

export default Todo;

Any help or direction would be greatly appreciated!

CodePudding user response:

You need to pass the index of the element you want to delete. In the delete handler filter by elements with indices not equal to the passed index

const deleteItem = (index) => {
  setTodos(todos => todos.filter((item, i) => i !== index));
};

And in the mapping

const TodoList = (props) => {
  return (
    <div className="todo-list">
      <ul>
        {props.items.map((todo, i) => (
          <Todo
            index={i}
            key={todo.id}
            title={todo.title}
            date={todo.date}
            handleDelete={() => props.handleDelete(i)}
          />
        ))}
      </ul>
    </div>
  );
};

It may be better to use the id property instead.

const deleteItem = (id) => {
  setTodos(todos => todos.filter((item) => item.id !== id));
};

...

const TodoList = (props) => {
  return (
    <div className="todo-list">
      <ul>
        {props.items.map((todo, i) => (
          <Todo
            index={i}
            key={todo.id}
            title={todo.title}
            date={todo.date}
            handleDelete={() => props.handleDelete(todo.id)}
          />
        ))}
      </ul>
    </div>
  );
};

And to avoid the anonymous callback in the child component, declare handleDelete as a curried function.

const deleteItem = (id) => () => {
  setTodos(todos => todos.filter((item) => item.id !== id));
};

...

const TodoList = (props) => {
  return (
    <div className="todo-list">
      <ul>
        {props.items.map((todo, i) => (
          <Todo
            index={i}
            key={todo.id}
            title={todo.title}
            date={todo.date}
            handleDelete={props.handleDelete(todo.id)}
          />
        ))}
      </ul>
    </div>
  );
};

CodePudding user response:

First you need to pass your todo id into handle delete then you can access id there

{ props.items.map((todo, i) => (
          <Todo
            index={i}
            key={todo.id}
            title={todo.title}
            date={todo.date}
            handleDelete={()=> props.handleDelete(todo.id)}
          />
        ))}

You access id here

  const deleteItem = (todoId) => {
     const newTodos = todos.filter((item) => item.id !== todoId;
    setTodos(newTodos);
  };

CodePudding user response:

Add the data-index attribute in your Todo.js

<li data-index={props.index} onClick={props.handleDelete} className="todo-item">
  <h2>{props.title}</h2>
  <span>
   {day}, {month}, {year}
  </span>
</li>

and delete it in deleteTodo

const deleteItem = (e) => {
    const newTodos = todos.filter((item) =>  item.index !==  e.currentTarget.dataset.index)
    setTodos(newTodos);
  };
  • Related