9

I have the state values as

this.state = {
    emp: [
        {id: "1", name: "A"}
        {id: "2", name: "B"}
        {id: "3", name: "B"}
    ]
}

How can I add an array like var arr = {id:"4", name:"D"} to the state emp without removing the current values of array. I just want to append the new array of values to the current state array. Can anyone help?

1
  • please make var arr = [{id: "4", name: "D"}] Commented Jun 5, 2018 at 9:45

4 Answers 4

22

In modern JavaScript you can use the spread operator:

Add a single item

addItem = item => {
  this.setState({
    emp: [
      ...this.state.emp,
      item 
    ]
  })
}

Add multiple items:

addItems = items => {
  this.setState({
    emp: [
      ...this.state.emp,
      ...items
    ]
  })
}

The spread operator places all the elements in this.state.emp in a new array instance and item gets appended as the last element.

You should not mutate a component's state with other means than setState as your rendered data will get out of sync.

Sign up to request clarification or add additional context in comments.

5 Comments

Maybe you could provide some details of why this should be the way to do it. This should be the accepted answer but flesh it out a little. Why you should use setState and what the spread operator does.
This is not working. It appends as nested array inside emp
your example is a bit unclear. you are talking about an array but the code in the text shows just an object.
@lipp's answer is the correct way to append to an array in React state. Can you give an example of the input and incorrect output you're getting when using his answer?
Yes this works now. I used your example for multiple items. Thanks @lipp
6

just use concat

this.setState({ emp: this.state.emp.concat('new value') })

The reasons why concat is better than push, unshift are

Array.push

Array.prototype.push allows us to push elements to the end of an array. This method does not return a new copy, rather mutates the original array by adding a new element and returns the new length property of the object upon which the method was called.

Array.unshift

To add elements to the very beginning of an array. Just as push, unshift does not return a new copy of the modified array, rather the new length of the array

Both the ways changes the mutation state of an array. A mutation term is meant to be unchanged because it is our original source.

array.concat

The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.

However, You Object.assign() too, that creates a deep copy of object assigned to it.

let emp = Object.assign([],this.state.emp); //type of an array

result enter image description here

2 Comments

I was literally in the middle of typing a comment about mutating with push() when you updated it haha :P
@Jayce444, Just realized what could go wrong literally :D
4

You need to update if using functional setState(since you are updating state based on prevState) and spread syntax like

this.setState(prevState => ({
    emp: [
        ...prevState.emp, 
        {id:"4",name:"c"}
    ]
}))

1 Comment

This appends as a nested array to the array value. Not the required result
0

If using a functional component, voila a simple example:

const [hiddenDivs, setHiddenDivs] = useState([1, 2, 3, 4]);

const handleCatDivTitleClick = (divNum: number) => {
   if (hiddenDivs.includes(divNum)) {
      setHiddenDivs(hiddenDivs.filter((d) => d !== divNum));  //REMOVE FROM ARRAY
   } else {
      setHiddenDivs([...hiddenDivs, divNum]);  //ADD TO ARRAY
   }
};

<div class={`${style.catDiv} ${hiddenDivs.includes(1) ? style.catDivHide : ''}`}>
   <div class={style.catTitle} onClick={() => handleCatDivTitleClick(1)}>
      Imagine a list of categories like this. All begin "hidden" (shrunk-up).
   </div>
</div>
<div class={`${style.catDiv} ${hiddenDivs.includes(2) ? style.catDivHide : ''}`}>
   <div class={style.catTitle} onClick={() => handleCatDivTitleClick(2)}>
       You want to shrink/expand category based on clicking title.
   </div>
</div>
<div class={`${style.catDiv} ${hiddenDivs.includes(3) ? style.catDivHide : ''}`}>
   <div class={style.catTitle} onClick={() => handleCatDivTitleClick(3)}>
      Basically, a home-rolled accordian-type display.
   </div>
</div>

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.