290

The story is, I should be able to put Bob, Sally and Jack into a box. I can also remove either from the box. When removed, no slot is left.

people = ["Bob", "Sally", "Jack"]

I now need to remove, say, "Bob". The new array would be:

["Sally", "Jack"]

Here is my react component:

...

getInitialState: function() {
  return{
    people: [],
  }
},

selectPeople(e){
  this.setState({people: this.state.people.concat([e.target.value])})
},

removePeople(e){
  var array = this.state.people;
  var index = array.indexOf(e.target.value); // Let's say it's Bob.
  delete array[index];
},

...

Here I show you a minimal code as there is more to it (onClick etc). The key part is to delete, remove, destroy "Bob" from the array but removePeople() is not working when called. Any ideas? I was looking at this but I might be doing something wrong since I'm using React.

1
  • The problem is that you're mutating (changing) your collection. The collection still points to the same array reference, thus it is not seen as changed (the variable still points to the same array), therefore it will not re-render. One common implementation is to copy the original state, modify it, then overwrite the current state with the copy which will be a new array reference and be seen as changed, thus causing a render update. Commented Jan 19, 2022 at 0:19

20 Answers 20

380

When using React, you should never mutate the state directly. If an object (or Array, which is an object too) is changed, you should create a new copy.

Others have suggested using Array.prototype.splice(), but that method mutates the Array, so it's better not to use splice() with React.

Easiest to use Array.prototype.filter() to create a new array:

removePeople(e) {
    this.setState({people: this.state.people.filter(function(person) { 
        return person !== e.target.value 
    })});
}
Sign up to request clarification or add additional context in comments.

7 Comments

Yes this is declarative way. An alternate method using prevState and arrow functions: this.setState(prevState => ({ people: prevState.people.filter(person => person !== e.target.value) }));
or using the index: this.state.people.filter((_, i) => i !== index)
there is slice that is imutable and splice that mutable
Issue with this answer is if you have several persons with the same name, you will remove all of these. Using the index is safer in cases where you may have dupes
@Cassian omg thanks. Took me a while to finally find this info... I couldn't tell the small difference (1 character) between splice and slice. I was using slice but had read about splice.. Sigh.
|
300

To remove an element from an array, just do:

array.splice(index, 1);

In your case:

removePeople(e) {
  var array = [...this.state.people]; // make a separate copy of the array
  var index = array.indexOf(e.target.value)
  if (index !== -1) {
    array.splice(index, 1);
    this.setState({people: array});
  }
},

7 Comments

What if I have another state object other than people? will it be discarded?
I recommend using Array.from(this.state.items) instead of the spread operator in this case. This is because Array.from is specifically intended for this use.
what is 'e' in this case? what value should i pass to call removePeople() function? I'm sorry if its a very basic question but I'm just a learner.
Small suggestion, add a check for "index !== -1" before splicing the array to prevent unwanted removals.
this must be the worst thing about react native
|
63

Here is a minor variation on Aleksandr Petrov's response using ES6

removePeople(e) {
    let filteredArray = this.state.people.filter(item => item !== e.target.value)
    this.setState({people: filteredArray});
}

Comments

41

Simple solution using slice without mutating the state

const [items, setItems] = useState(data);
const removeItem = (index) => {
  setItems([
             ...items.slice(0, index),
             ...items.slice(index + 1)
           ]);
}

Comments

23

Use .splice to remove item from array. Using delete, indexes of the array will not be altered but the value of specific index will be undefined

The splice() method changes the content of an array by removing existing elements and/or adding new elements.

Syntax: array.splice(start, deleteCount[, item1[, item2[, ...]]])

var people = ["Bob", "Sally", "Jack"]
var toRemove = 'Bob';
var index = people.indexOf(toRemove);
if (index > -1) { //Make sure item is present in the array, without if condition, -n indexes will be considered from the end of the array.
  people.splice(index, 1);
}
console.log(people);

Edit:

As pointed out by justin-grant, As a rule of thumb, Never mutate this.state directly, as calling setState() afterward may replace the mutation you made. Treat this.state as if it were immutable.

The alternative is, create copies of the objects in this.state and manipulate the copies, assigning them back using setState(). Array#map, Array#filter etc. could be used.

this.setState({people: this.state.people.filter(item => item !== e.target.value);});

1 Comment

Make sure not to use splice or any method that changes your state variable directly. Instead, you'll want to make a copy of the array, remove the item from the copy, and then pass the copy into setState. Other answers have details about how to do this.
23

filter method is the best way to modify the array without touching the state.

It returns a new array based on the condition.

In your case filter check the condition person.id !== id and create a new array excluding the item based on condition.

const [people, setPeople] = useState(data);

const handleRemove = (id) => {
   const newPeople = people.filter((person) => person.id !== id);

   setPeople( newPeople);
 };

<button onClick={() => handleRemove(id)}>Remove</button>

Not advisable: But you can also use an item index for the condition if you don't have any id.

index !== itemIndex

Comments

20

Easy Way To Delete Item From state array in react:

when any data delete from database and update list without API calling that time you pass deleted id to this function and this function remove deleted recored from list

export default class PostList extends Component {
  this.state = {
      postList: [
        {
          id: 1,
          name: 'All Items',
        }, {
          id: 2,
          name: 'In Stock Items',
        }
      ],
    }


    remove_post_on_list = (deletePostId) => {
        this.setState({
          postList: this.state.postList.filter(item => item.post_id != deletePostId)
        })
      }
  
}

3 Comments

Can you explain how this differs from the 8 other answers on this three year old question? From review
in above code it will recreate new array of data but skip "deletePostId" this id
use item.post_id !== deletePostId
6

This is your current state variable:

const [animals, setAnimals] = useState(["dogs", "cats", ...])

Call this function and pass the item you would like to remove.

removeItem("dogs")

const removeItem = (item) => {
    setAnimals((prevState) =>
      prevState.filter((prevItem) => prevItem !== item)
    );
  };

your state variable now becomes:

["cats", ...]

Another way of doing it is by using useState hook. Check docs: https://reactjs.org/docs/hooks-reference.html#functional-updates It states: Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax as shown below or use useReducer hook.

const [state, setState] = useState({});
setState(prevState => {
  return {...prevState, ...updatedValues};
});

Comments

5

Just filter out deleted item and update the state with remaining items again,

let remainingItems = allItems.filter((item) => {return item.id !== item_id});
    
setItems(remainingItems);

Comments

3

Some answers mentioned using 'splice', which did as Chance Smith said mutated the array. I would suggest you to use the Method call 'slice' (Document for 'slice' is here) which make a copy of the original array.

1 Comment

Can you provide a minimal example to illustrate what you're discussing here? Thanks.
2
const [people, setPeople] = useState(data);

const handleRemove = (id) => {
   const newPeople = people.filter((person) => { person.id !== id;
     setPeople( newPeople );
     
   });
 };

<button onClick={() => handleRemove(id)}>Remove</button>

1 Comment

Your code is not complete, please check and rectify it. Also make sure to explain the code as well instead of just providing the code.
1

If you use:

const[myArr, setMyArr] = useState([]);

for add:

setMyArr([...myArr, value]);

and for remove:

let index = myArr.indexOf(value);
if(index !== -1)
    setPatch([...myArr.slice(0, index), ...myArr.slice(index, myArr.length-1)]);

1 Comment

I came up with this one-liner: setMyArr(myArr.slice(0, myArr.length - 1));
0

It's Very Simple First You Define a value

state = {
  checked_Array: []
}

Now,

fun(index) {
  var checked = this.state.checked_Array;
  var values = checked.indexOf(index)
  checked.splice(values, 1);
  this.setState({checked_Array: checked});
  console.log(this.state.checked_Array)
}

1 Comment

Please don't do this. It mutates state directly. splice is in-place.
0
removePeople(e){
    var array = this.state.people;
    var index = array.indexOf(e.target.value); // Let's say it's Bob.
    array.splice(index,1);
}

Redfer doc for more info

1 Comment

This mutates state directly. Don't do this -- always treat state as immutable.
0

Almost all the answers here seem to be for class components, here's a code that worked for me in a functional component.

const [arr,setArr]=useState([]);
const removeElement=(id)=>{
    var index = arr.indexOf(id)
    if(index!==-1){
      setArr(oldArray=>oldArray.splice(index, 1));
    }
}

1 Comment

splice doesn't return the new array. It's in-place.
0

Removing an element with a certain value // Note filter function always returns a new array.

const people = ["Bob", "Sally", "Jack"]
    
const removeEntry = (remove) => {
const upDatePeople = people.filter((Person) =>{
return Person !== remove
});
console.log(upDatePeople)
//Output: [ 'Sally', 'Jack' ]
}
removeEntry("Bob");

1 Comment

Welcome to SO! Please don't post code-only answers but add a little textual explanation about how and why your approach works and what makes it different from the other answers given. You can find out more at our "How to write a good answer" page.
0

This way seems simplest to me for deleting from state array in reactJS.

const handleSelectedTaxDec = (dec, action) => {
  const newState = selectedTaxDec.filter((tax) => tax?._id !== dec?._id);
  setSelectedTaxDec(newState);

};

Comments

0

when you want to remove an item from the state in react you will use the ES6 filter.

const [bookmark, setBookMark] = useState([])
const deleteItem = (id) => {
  const newArray = bookmark.filter(item => item.id !== id);
  setBookMark(deletId)
}

Comments

-1

You forgot to use setState. Example:

removePeople(e){
  var array = this.state.people;
  var index = array.indexOf(e.target.value); // Let's say it's Bob.
  delete array[index];
  this.setState({
    people: array
  })
},

But it's better to use filter because it does not mutate array. Example:

removePeople(e){
  var array = this.state.people.filter(function(item) {
    return item !== e.target.value
  });
  this.setState({
    people: array
  })
},

1 Comment

"But it's better to use filter because it does not mutate array" -- why even show the top version, since it's confusing, incorrect and buggy? I understand you're trying to work with OP's example, but delete on state is fundamentally broken, even with setState.
-3
const [randomNumbers, setRandomNumbers] = useState([111,432,321]);
const numberToBeDeleted = 432;

// Filter (preferred)
let newRandomNumbers = randomNumbers.filter(number => number !== numberToBeDeleted)
setRandomNumbers(newRandomNumbers);

//Splice (alternative)
let indexOfNumberToBeDeleted = randomNumbers.indexOf(numberToBeDeleted);
let newRandomNumbers = Array.from(randomNumbers);
newRandomNumbers.splice(indexOfNumberToBeDeleted, 1);
setRandomNumbers(newRandomNumbers);


//Slice (not preferred - code complexity)
let indexOfNumberToBeDeleted = randomNumbers.indexOf(numberToBeDeleted);
let deletedNumber = randomNumbers.slice(indexOfNumberToBeDeleted, indexOfNumberToBeDeleted+1);
let newRandomNumbers = [];
for(let number of randomNumbers) {
    if(deletedNumber[0] !== number)
        newRandomNumbers.push(number);
};
setRandomNumbers(newRandomNumbers);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.