How to push element inside useState array React hook? Is that as an old method in react state? Or something new?
E.g. setState push example ?
How to push element inside useState array React hook? Is that as an old method in react state? Or something new?
E.g. setState push example ?
When you use useState
, you can get an update method for the state item:
const [theArray, setTheArray] = useState(initialArray);
then, when you want to add a new element, you use that function and pass in the new array or a function that will create the new array. Normally the latter, since state updates are asynchronous and sometimes batched:
setTheArray(oldArray => [...oldArray, newElement]);
Sometimes you can get away without using that callback form, if you only update the array in handlers for certain specific user events like click
(but not like mousemove
):
setTheArray([...theArray, newElement]);
The events for which React ensures that rendering is flushed are the "discrete events" listed here.
Live Example (passing a callback into setTheArray
):
const {useState, useCallback} = React;
function Example() {
const [theArray, setTheArray] = useState([]);
const addEntryClick = () => {
setTheArray(oldArray => [...oldArray, `Entry ${oldArray.length}`]);
};
return [
<input type="button" onClick={addEntryClick} value="Add" />,
<div>{theArray.map(entry =>
<div>{entry}</div>
)}
</div>
];
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
Because the only update to theArray
in there is the one in a click
event (one of the "discrete" events), I could get away with a direct update in addEntry
:
const {useState, useCallback} = React;
function Example() {
const [theArray, setTheArray] = useState([]);
const addEntryClick = () => {
setTheArray([...theArray, `Entry ${theArray.length}`]);
};
return [
<input type="button" onClick={addEntryClick} value="Add" />,
<div>{theArray.map(entry =>
<div>{entry}</div>
)}
</div>
];
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
useEffect
example...? –
Disabled useEffect
has an empty dependency list []
, it will be executed only during the first render. So the value of theArray
inside the effect will always be initialArray
. In situations where setTheArray([...initialArray, newElement])
would not make sense, and when theArray
constant will always equal to initialValue
, then functional updates are needed. –
Avisavitaminosis forceUpdate
(in a class component), or B) changing some other state member (to trigger a re-render). But any component using the array that optimizes by not re-rendering when the array doesn't change (memo
, ... –
Disabled PureComponent
, etc.) will be confused by it. Or you could play games with a Proxy
(where you replace the Proxy
rather than copying the array), and provide the proxy to anything else that uses it. I wouldn't be surprised if that ended up being more overhead, rather than less, than just copying the array. –
Disabled To expand a little further, here are some common examples. Starting with:
const [theArray, setTheArray] = useState(initialArray);
const [theObject, setTheObject] = useState(initialObject);
Push element at end of array
setTheArray(prevArray => [...prevArray, newValue])
Push/update element at end of object
setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));
Push/update element at end of array of objects
setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);
Push element at end of object of arrays
let specificArrayInObject = theObject.array.slice();
specificArrayInObject.push(newValue);
const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
theObject(newObj);
Here are some working examples too. https://codesandbox.io/s/reacthooks-push-r991u
You can append array of Data at the end of custom state:
const [vehicleData, setVehicleData] = React.useState<any[]>([]);
setVehicleData(old => [...old, ...newArrayData]);
For example, In below, you appear an example of axios:
useEffect(() => {
const fetchData = async () => {
const result = await axios(
{
url: `http://localhost:4000/api/vehicle?page=${page + 1}&pageSize=10`,
method: 'get',
}
);
setVehicleData(old => [...old, ...result.data.data]);
};
fetchData();
}, [page]);
Most recommended method is using wrapper function and spread operator together. For example, if you have initialized a state called name
like this,
const [names, setNames] = useState([])
You can push to this array like this,
setNames(names => [...names, newName])
Hope that helps.
// Save search term state to React Hooks with spread operator and wrapper function
// Using .concat(), no wrapper function (not recommended)
setSearches(searches.concat(query))
// Using .concat(), wrapper function (recommended)
setSearches(searches => searches.concat(query))
// Spread operator, no wrapper function (not recommended)
setSearches([...searches, query])
// Spread operator, wrapper function (recommended)
setSearches(searches => [...searches, query])
https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc
setTheArray([...theArray, newElement]);
is the simplest answer but be careful for the mutation of items in theArray. Use deep cloning of array items.
I tried the above methods for pushing an object into an array of objects in useState but had the following error when using TypeScript:
Type 'TxBacklog[] | undefined' must have a 'Symbol.iterator' method that returns an iterator.ts(2488)
The setup for the tsconfig.json was apparently right:
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext",
"es6",
],
This workaround solved the problem (my sample code):
Interface:
interface TxBacklog {
status: string,
txHash: string,
}
State variable:
const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();
Push new object into array:
// Define new object to be added
const newTx = {
txHash: '0x368eb7269eb88ba86..',
status: 'pending'
};
// Push new object into array
(txBacklog)
? setTxBacklog(prevState => [ ...prevState!, newTx ])
: setTxBacklog([newTx]);
if you want to push after specific index you can do as below:
const handleAddAfterIndex = index => {
setTheArray(oldItems => {
const copyItems = [...oldItems];
const finalItems = [];
for (let i = 0; i < copyItems.length; i += 1) {
if (i === index) {
finalItems.push(copyItems[i]);
finalItems.push(newItem);
} else {
finalItems.push(copyItems[i]);
}
}
return finalItems;
});
};
lets assume you have this state :
const [array, set_array] = useState([]);
then in your function push to your array like this :
set_array([...array, new_array]);
© 2022 - 2024 — McMap. All rights reserved.
setTheArray(currentArray => [...currentArray, newElement])
if the above does not work. Most likely inuseEffect(...theArray..., [])
, it's important to realize thattheArray
is a constant, so functional updates are needed for values from future renders – Avisavitaminosis