React array state not pushing value

Viewed 83

I want to update my state array with new values. Basically, I want to add some new values to the array. but couldn't able to do that

const [values, setValues] = useState(["data1", "data2"]);

const newData = [["data 43", "data 1.1"],["data 65", "data 2.2"] ]

newData.map((item) => {
  setValues([...values, item[1]]);
});
 
returns ["data1", "data2", "data2.2"]

what i want is ["data1", "data2", "data 1.1", "data 2.2"] I just want to store 2nd value of array

4 Answers

Issue

  1. Using Array.prototype.map is for mapping an existing array to a new array, not for issuing side-effects like updating React state or pushing into other array.
  2. When enqueuing state updates in a loop you must use a functional state update to correctly update from the previous state instead of the state from the previous render cycle.

Solution

const [values, setValues] = useState(["data1", "data2"]);

...

["data3", "data4", "data5"].forEach((item) => {
  setValues(values => [...values, item]);
});

Since you are really just appending one array to the other you can make this simpler by removing the looping. (Well, you are still looping, but now the loop is within the state updater function so you avoid the state-looping issue)

setValues(values => [...values, ...["data3", "data4", "data5"]]);

or

setValues(values => values.concat(["data3", "data4", "data5"]));

UPDATE

Use the functional state update to shallow copy the previous values and map the new data to an array of just the second element and shallow copy that new result.

const newData = [
  ["data 1", "data 1.1"],
  ["data 2", "data 2.2"]
];

...

const [values, setValues] = useState(["data 1", "data 2"]);

...

setValues((values) => [
  ...values,
  ...newData.map(([, newValue]) => newValue) // *
]);

* newData is an array of arrays, [, newValue] in the callback uses destructuring assignment to "skip" the 0th element and assigns the 1th element to a variable newValue and returns this value for the mapping.

Edit

To remove duplicates created in new data, use a Set to remove them:

setValues((values) => [
  ...new Set([...values, ...newData.map(([, newValue]) => newValue)])
]);

Demo

Edit react-array-state-not-pushing-value

const newArr = ['data3','data4','data5'];

setValues((prev)=>([...prev, ...newArr]));

You can do like this

UPDATED

const newData = [["data 43", "data 1.1"],["data 65", "data 2.2"] ]
setValues((prev)=>([...prev, ...newData.flat()]));

If all nested arrays will be of equal length you can use something like this to iterate over

newData = [["data 1", "data 1.1"],["data 2", "data 2.2"]]
const rowLength = newData[0].length
const returnArr = []
for(let i=0; i<rowLength; i++){
  returnArr.push(newData.map(row => row[i]))
}
console.log(returnArr.flat())

setData comes from your useState and is kind of asynchrone. You can't use it in a loop. What you want to do is prepare your final data object, and call setData only once with it.

// No change here
const [values, setValues] = useState(["data1", "data2"]);
const newData = [["data 1", "data 1.1"],["data 2", "data 2.2"] ]

// Flatten the array
const finalData = newData.flat();

// Update the state only once
setValues(finalData);
Related