drome845
drome845

Reputation: 179

Deleting Specific Item From Array in React using Functional Components/Hooks

I am trying to delete an item in an array. However, my delete button is not executing my code and the array remains unchanged. I am not sure what to do.

My code is below:

//App.js

import React, { useState } from "react";
import Overview from "./components/Overview";

function App() {
  const [task, setTask] = useState("");
  const [tasks, setTasks] = useState([]);

  function handleChange(e) {
    setTask(e.target.value);
  }

  function onSubmitTask(e) {
    e.preventDefault();
    setTasks(tasks.concat(task));
    setTask("");
  }

  //error happening here????---------------------------------------------------
  function removeTask(itemId) {
      setTasks(prevState => prevState.filter(({ id }) => id !== itemId));
  }


  return (
    <div className="col-6 mx-auto mt-5">
      <form onSubmit={onSubmitTask}>
        <div className="form-group">
          <label htmlFor="taskInput">Enter task</label>
          <input
            onChange={handleChange}
            value={task}
            type="text"
            id="taskInput"
            className="form-control"
          />
        </div>
        <div className="form-group">
          <button type="submit" className="btn btn-primary">
            Add Task
          </button>
        </div>
      </form>
      <Overview tasks={tasks} removeTask={removeTask} />
    </div>
  );
}

export default App;

Child Component:

import React from "react";

function Overview(props) {
  const { tasks, removeTask } = props;
  console.log(tasks)
  return (
    <>
      {tasks.map((task, index) => {
        return (
          <>
            <p key={index}>
              #{index + 1} {task}
            </p>
            //this onClick isn't doing anything-------------------------------------
            <button onClick={() => removeTask(index)}>Delete Task</button>
          </>
        );
      })}
    </>
  );
}
export default Overview;

My 'tasks' state gives me an array, with items inside as strings. However, when I tried to filter the array, that didn't work. So instead of filtering by value, I tried to filter by id/index. Since the index would match it I thought that would remove the item from the array, even if there is just one item, it doesn't remove anything and the delete button just console logs the given array.

Any help would be greatly appreciated.

Upvotes: 1

Views: 2262

Answers (2)

Drew Reese
Drew Reese

Reputation: 203146

Issue

Your delete method consumes an item id, but you pass it an index in the button's onClick handler.

Solution

Choose one or the other of id or index, and remain consistent.

Using id

function removeTask(itemId) {
  setTasks(prevState => prevState.filter(({ id }) => id !== itemId));
}

...

<button onClick={() => removeTask(task.id)}>Delete Task</button>

Using index

function removeTask(itemIndex) {
  setTasks(prevState => prevState.filter((_, index) => index !== itemIndex));
}

...

<button onClick={() => removeTask(index)}>Delete Task</button>

Since it doesn't appear your tasks are objects with an id property I suggest adding an id to your tasks. This will help you later when you successfully delete a task from you list since you'll also want to not use the array index as the react key since you expect to mutate your tasks array.

App.js

import { v4 as uuidV4 } from 'uuid';

...

function onSubmitTask(e) {
  e.preventDefault();
  setTasks(prevTasks => prevTasks.concat({
    id: uuidV4(), // <-- generate new id
    task
  }));
  setTask("");
}

function removeTask(itemId) {
  setTasks(prevState => prevState.filter(({ id }) => id !== itemId));
}

Child

function Overview({ tasks, removeTask }) {
  return (
    {tasks.map(({ id, task }, index) => { // <-- destructure id & task
      return (
        <Fragment key={id}> // <-- react key on outer-most element
          <p>
            #{index + 1} {task}
          </p>
          <button onClick={() => removeTask(id)}>Delete Task</button>
        </>
      );
    })}
  );
}

Upvotes: 1

Kalhan.Toress
Kalhan.Toress

Reputation: 21901

I think you need to pass the taskId instead of index here

<button onClick={() => removeTask(task.id /*index*/)}>Delete Task</button>

because removeTask function is dealing with taskId not with the index


However it's looks like you don't have id field on tasks even though you assuming it is there in setTasks(prevState => prevState.filter(({ id }) => id !== itemId));, so if you want to keep removing task by index, change removeTask as below.

function removeTask(index) { // remove by index
    setTasks(prevState => {
        const tasks = [...prevState]; // create new array based on current tasks
        tasks.splice(index, 1); // remove task by index
        return tasks; // return altered array
    });
}

demo

Upvotes: 1

Related Questions