Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing object from array using hooks (useState)

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!

like image 890
collinswade408 Avatar asked Aug 03 '19 19:08

collinswade408


People also ask

How do you remove an object from useState array?

We can remove an element by its index by setting the new state for the array as follows: setProductsArray((products) => products. filter((_, index) => index !== 0));

How do I remove a specific element from an array in React?

To remove an element from an array of objects in React: Use the filter() method to iterate over the array. On each iteration check if a certain condition is met. The filter method returns an array containing only the elements that satisfy the condition.

How do I clear the useState array in React?

If you want to clear out the array you can just set it to an empty array when calling setTokenArray .

Can useState be an array of objects?

To type the useState hook as an array of objects in React, use the hook's generic, e.g. const [employees, setEmployees] = useState<{salary: number; name: string}[]>([]) . The state variable can be initialized to an empty array and will only accept objects of the specified type.


4 Answers

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);
like image 62
Chris Ngo Avatar answered Oct 12 '22 23:10

Chris Ngo


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>
        </>
    )}
like image 30
Will Jenkins Avatar answered Oct 13 '22 00:10

Will Jenkins


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>
    ))}

)
like image 22
Mahesh Samudra Avatar answered Oct 13 '22 00:10

Mahesh Samudra


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);
}
like image 1
William Gunawan Avatar answered Oct 12 '22 23:10

William Gunawan