Ilja
Ilja

Reputation: 46547

Correct way to push into state array

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?

Upvotes: 305

Views: 704594

Answers (17)

Klesun
Klesun

Reputation: 13747

If your array is too large for conventional [...oldArray, newValue] to be feasible (as it is O(N) complexity contrary to the O(1) complexity of .push() operation), you can wrap the array in an object to make sure to notify react of the update every time you mutate the array:

this.state = {
    myArrayUpdateWrapper: {
        myArray: [],
    },
};
...
function pushToStateArray(newValue) {
    const { myArray } = this.state.myArrayUpdateWrapper;
    myArray.push(newValue);
    this.setState({ myArrayUpdateWrapper: { myArray } });
}

I believe this approach is both compliant with React principles and is efficient too. Very surprised that nobody mentioned it so far, even in the downvoted answers.

Upvotes: 0

Márton Tamás
Márton Tamás

Reputation: 2809

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

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

Upvotes: 216

Ammad Ahmed
Ammad Ahmed

Reputation: 19

It is the best and simplest way in reactJS if you working in functional components!

setSelectedTaxDec((oldArray) => [...oldArray, dec]);

oldArray is the previousState in which I am pushing the new value dec, is the value I am pushing in this state array

you can avoid pushing the same item again by doing this

if (selectedTaxDec.includes(dec)) {
    return;
  } else {
    setSelectedTaxDec((oldArray) => [...oldArray, dec]);
  }

Upvotes: 0

Mostafa Mohammadzadeh
Mostafa Mohammadzadeh

Reputation: 911

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)]);

Upvotes: 1

Panagiss
Panagiss

Reputation: 3750

Functional Components & React Hooks

const [array,setArray] = useState([]);

Push value at the end:

setArray(oldArray => [...oldArray,newValue] );

Push value at the start:

setArray(oldArray => [newValue,...oldArray] );

Upvotes: 243

Mudassir Kidwai
Mudassir Kidwai

Reputation: 57

  setState([...prevState, {
    label: newState.name,
    value: newState.id
  }]);

Was working with the dropdowns and wanted to implement this scenario there, i found this simple solution for dropdown with multiple values.

Upvotes: 3

Nevin
Nevin

Reputation: 375

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

Upvotes: -1

Rajesh N
Rajesh N

Reputation: 6693

Using react hooks, you can do following way

const [countryList, setCountries] = useState([]);


setCountries((countryList) => [
        ...countryList,
        "India",
      ]);

Upvotes: 15

Ahmed Muhammed  Elsaid
Ahmed Muhammed Elsaid

Reputation: 190

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

Upvotes: 0

Sachin Muthumala
Sachin Muthumala

Reputation: 765

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

Upvotes: 23

KARTHIKEYAN.A
KARTHIKEYAN.A

Reputation: 20168

In the following way we can check and update the objects

this.setState(prevState => ({
    Chart: this.state.Chart.length !== 0 ? [...prevState.Chart,data[data.length - 1]] : data
}));

Upvotes: 2

Mahgolsadat Fathi
Mahgolsadat Fathi

Reputation: 3325

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

Upvotes: 2

Hemadri Dasari
Hemadri Dasari

Reputation: 34014

Never recommended to mutate the state directly.

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

Upvotes: 165

Hamid Hosseinpour
Hamid Hosseinpour

Reputation: 147

This Code work for me :

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

Upvotes: 4

Aliaksandr Sushkevich
Aliaksandr Sushkevich

Reputation: 12384

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

Upvotes: 316

Christoph
Christoph

Reputation: 968

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

Upvotes: 26

Ginden
Ginden

Reputation: 5316

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'].

Upvotes: 17

Related Questions