Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I seem to be having issues pushing data into a state array. I am trying to achieve it this way:

this.setState({ myArray: this.state.myArray.push('new value') })

But I believe this is incorrect way and causes issues with mutability?

Array.push returns the new length of the array instead of returning new array which causes issue – Bharat Jan 13, 2022 at 7:36

Using es6 it can be done like this:

this.setState({ myArray: [...this.state.myArray, 'new value'] }) //simple value
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] }) //another array

Spread syntax

I did the same, there are two cases myArray can have values and it won't. so in that, if it has already values, it works perfectly fine. But in no data..it does not update state with 'new value'. Any soln ? – Krina Soni Mar 8, 2018 at 9:17 It should work with any arrays, doesn't matter if it has values or not it will be destructured anyway. Maybe there is something wrong in other place. Could you please show an example of your code? – Aliaksandr Sushkevich Mar 8, 2018 at 18:52 hi Please refer my comment under @Tamas answer. It was just a sample in console. I tried myArray: [...this.state.myArray, 'new value'] to update my state array.But it concats only the last value.Could you plz tell me the solution? – Johncy Aug 31, 2018 at 13:10 @Johncy I’m not sure if your issue is related to this question, try to ask a separate question and describe the expected behavior and I’ll try to help you. – Aliaksandr Sushkevich Aug 31, 2018 at 17:09 Per the React docs: "Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state." In the case of modifying an array, since the array already exists as a property of this.state and you need to reference its value to set a new value, you should use the form of setState() that accepts a function with the previous state as an argument. Example: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] })); See: reactjs.org/docs/… – Bungle Feb 9, 2019 at 2:25

Array push returns length

this.state.myArray.push('new value') returns the length of the extended array, instead of the array itself.Array.prototype.push().

I guess you expect the returned value to be the array.

Immutability

It seems it's rather the behaviour of React:

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.React.Component.

I guess, you would do it like this (not familiar with React):

var joined = this.state.myArray.concat('new value');
this.setState({ myArray: joined })
                @Si8 Well, I don't use React too much unfortunately. But the docs say:  setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.  So I guess it's just not updated at that moment right after setting it. Could You please post a code example, where we can see which point You are setting and logging it, please?
– Márton Tamás
                Jul 22, 2019 at 10:36
                Thanks for the response. It's async so it won't show you the changes right away. However setState does have a callback which did display the correct value. Thanks again.
– Si8
                Jul 22, 2019 at 13:58
                w3schools.com/jsref/jsref_concat_array.asp    concat  concatenates two arrays (not array and string) ,  .concat('new value');   should be  .concat(['new value']);
– Manohar Reddy Poreddy
                Oct 19, 2019 at 15:22
                @ManoharReddyPoreddy Non-array values are perfectly valid for the concat() method. See: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… (Arrays and/or values to concatenate into a new array.)
– Márton Tamás
                Oct 20, 2019 at 19:37
                Short modification - the snippet for push value at the beginning shall be: setArray(oldArray => [newValue,...oldArray] );
– Ndrslmpk
                Nov 4, 2021 at 11:20
                @SouvikRay you can use Array.concat to merge two arrays and return new array. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
– Bharat
                Jan 13, 2022 at 7:38

The recommended approach in later React versions is to use an updater function when modifying states to prevent race conditions:

Push string to end of the array

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new value"]

Push string to beginning of the array

this.setState(prevState => ({
  myArray: ["new value", ...prevState.myArray]

Push object to end of the array

this.setState(prevState => ({
  myArray: [...prevState.myArray, {"name": "object"}]

Push object to beginning of the array

this.setState(prevState => ({
  myArray: [ {"name": "object"}, ...prevState.myArray]
                I used this answer. It also works for prepending into the array: this.setState((prevState) => ({       myArray: [values, ...prevState.myArray],     }));
– Gus
                Oct 23, 2018 at 17:34
                this is a much better approach than the accepted answer and does it the way React documentation recommends.
– Ian J Miller
                Jun 7, 2019 at 16:03
                Definitely +1ing this because the other answers don't follow the latest guidelines of using callbacks if mutating state with itself.
– Matt Fletcher
                Aug 29, 2019 at 13:30
                This creates a new array that becomes myArray: updatedContents rather than just leaving it as an array of the updated contents. If you're mapping the original array, this will cause an error due to the new structure. Is that intentional?
– Dr J
                Sep 4, 2021 at 19:36

You should not be operating the state at all. At least, not directly. If you want to update your array, you'll want to do something like this.

var newStateArray = this.state.myArray.slice();
newStateArray.push('new value');
this.setState(myArray: newStateArray);

Working on the state object directly is not desirable. You can also take a look at React's immutability helpers.

https://facebook.github.io/react/docs/update.html

I believe this answer to be the correct one although I would have liked to know why we can't operate on state, i.e. why it is not desirable. After a little digging I found the following React tutorial - Why Immutability is Important, which helped to fill in the missing info and the tutorial also uses .slice() to create a new array and preserve immutability. Thanks for the help. – BebopSong Apr 10, 2018 at 21:57

Here you can not push the object to a state array like this. You can push like your way in normal array. Here you have to set the state,

this.setState({ 
     myArray: [...this.state.myArray, 'new value'] 

You can use .concat method to create copy of your array with new data:

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

But beware of special behaviour of .concat method when passing arrays - [1, 2].concat(['foo', 3], 'bar') will result in [1, 2, 'foo', 3, 'bar'].

Using react hooks, you can do following way

const [countryList, setCountries] = useState([]);
setCountries((countryList) => [
        ...countryList,
        "India",
                setCountries((countryList) => [         ...countryList,        {id:1, name:'india'},       ]);
– Rajesh N
                Jun 24, 2021 at 4:44
  .then(response => response.json())
  .then(json => {
  this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
                Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: How do I write a good answer?. Thanks
– sɐunıɔןɐqɐp
                Sep 24, 2018 at 7:27
                I tried this but to no avail. Here's my code fetch(`api.openweathermap.org/data/2.5/forecast?q=${this.searchBox.value + KEY} `) 		.then( response =>  response.json() ) 		.then( data => {  			this.setState({	reports: this.state.reports.push.apply(this.state.reports, data.list)});	 		}); 
– henrie
                Jul 31, 2019 at 1:07
                and i firstly initialized state as an empty array i.e this.state = { reports=[] }...pls i'll like to know what i'm doing wrong
– henrie
                Jul 31, 2019 at 1:11

React-Native

if u also want ur UI (ie. ur flatList) to be up to date, use PrevState: in the example below if user clicks on the button , it is going to add a new object to the list( both in the model and UI)

data: ['shopping','reading'] // declared in constructor
onPress={() => {this.setState((prevState, props) => {
return {data: [new obj].concat(prevState.data) };
})}}. 
this.setState(prevState => ({
    Chart: this.state.Chart.length !== 0 ? [...prevState.Chart,data[data.length - 1]] : data

you are breaking React principles, you should clone the old state then merge it with the new data, you shouldn't manipulate your state directly, your code should go like this

fetch('http://localhost:8080').then(response => response.json()).then(json ={this.setState({mystate[...this.state.mystate, json]}) })

I guess this is a little bit late for an answer but for those new to react

You can use this tiny package called immer

see this example: https://immerjs.github.io/immer/produce

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.