Removing object from array using hooks (useState)

ReactjsTypescriptReact Hooks

Reactjs Problem Overview


I have an array of objects. I need to add a function to remove an object from my array without using the "this" keyword.

I tried using updateList(list.slice(list.indexOf(e.target.name, 1))). This removes everything but the last item in the array and I'm not certain why.

const defaultList = [
{ name: "ItemOne" },
{ name: "ItemTwo" },
{ name: "ItemThree" }]

const [list, updateList] = useState(defaultList);

const handleRemoveItem = e => {
    updateList(list.slice(list.indexOf(e.target.name, 1)))
}

return (
    {list.map(item => {
        return ( 
            <>
            <span onClick={handleRemoveItem}>x </span>
            <span>{item.name}</span>
            </>
        )}
    }

)

EXPECTED: The clicked item will be removed from the list.
ACTUAL: The entire list gets removed, minus the last item in the array.

Thanks in advance for any input!

Reactjs Solutions


Solution 1 - Reactjs

First of all, the span element with the click event needs to have a name property otherwise, there will be no name to find within the e.target. With that said, e.target.name is reserved for form elements (input, select, etc). So to actually tap into the name property you'll have to use e.target.getAttribute("name")

Additionally, because you have an array of objects, it would not be effective to use list.indexOf(e.target.name) since that is looking for a string when you are iterating over objects. That's like saying find "dog" within [{}, {}, {}]

Lastly, array.slice() returns a new array starting with the item at the index you passed to it. So if you clicked the last-item, you would only be getting back the last item.

Try something like this instead using .filter(): codesandbox

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const App = () => {
  const defaultList = [
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
  ];

  const [list, updateList] = useState(defaultList);

  const handleRemoveItem = (e) => {
   const name = e.target.getAttribute("name")
    updateList(list.filter(item => item.name !== name));
  };

  return (
    <div>
      {list.map(item => {
        return (
          <>
            <span name={item.name} onClick={handleRemoveItem}>
              x
            </span>
            <span>{item.name}</span>
          </>
        );
      })}
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Solution 2 - Reactjs

You can use Array.filter to do this in a one-liner:

const handleRemoveItem = name => {
    updateList(list.filter(item => item.name !== name))
}

Eta: you'll also need to pass the name of your item in your onClick handler:

{list.map(item => {
    return ( 
        <>
        <span onClick={() =>handleRemoveItem(item.name)}>x </span>
        <span>{item.name}</span>
        </>
    )}

Solution 3 - Reactjs

I faced the same issue and came up with a solution using the answers to this question. I'm putting my final solution here because I had to use multiple answers to get there.

const defaultList = [
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
]

const [list, updateList] = useState(defaultList);

const handleRemoveItem = idx => {
    // assigning the list to temp variable
    const temp = [...list];

    // removing the element using splice
    temp.splice(idx, 1);

    // updating the list
    updateList(temp);
}

return (
    {list.map((item, idx) => (
      <div key={idx}>
        <button onClick={() => handleRemoveItem(idx)}>x </button>
        <span>{item.name}</span>
      </div>
    ))}

)

Solution 4 - Reactjs

I think this code will do

let targetIndex = list.findIndex((each) => {each.name == e.target.name});
list.splice(targetIndex-1, 1);

We need to check name value inside object so use findIndex instead. then cut the object start from target index to 1 array after target index.

Codepen

> From your comment your problem came from another part.

Change this view section

    return ( 
        <>
        <span onClick={() => handleRemoveItem(item) }>x </span>
        <span>{item.name}</span>
        </>
    )}

change function handleRemoveItem format

const handleRemoveItem = item => {
    list.splice(list.indexOf(item)-1, 1)
    updateList(list);
}

Solution 5 - Reactjs

Small improvement in my opinion to the best answer so far

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const App = () => {
  const defaultList = [
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
  ];

  const [list, updateList] = useState(defaultList);

  const handleRemoveItem = (item) => {
    updateList(list.filter(item => item.name !== name));
  };

  return (
    <div>
      {list.map(item => {
        return (
          <>
            <span onClick={()=>{handleRemoveItem(item)}}>
              x
            </span>
            <span>{item.name}</span>
          </>
        );
      })}
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Instead of giving a name attribute we just send it to the handle function

Solution 6 - Reactjs

This is because both slice and splice return an array containing the removed elements.

You need to apply a splice to the array, and then update the state using the method provided by the hook

const handleRemoveItem = e => {
    const newArr = [...list];
    newArr.splice(newArr.findIndex(item => item.name === e.target.name), 1)
    updateList(newArr)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questioncollinswade408View Question on Stackoverflow
Solution 1 - ReactjsChris NgoView Answer on Stackoverflow
Solution 2 - ReactjsWill JenkinsView Answer on Stackoverflow
Solution 3 - ReactjsMahesh SamudraView Answer on Stackoverflow
Solution 4 - ReactjsWilliam GunawanView Answer on Stackoverflow
Solution 5 - ReactjsItzhak TzadokView Answer on Stackoverflow
Solution 6 - ReactjsMorphyishView Answer on Stackoverflow