Assume the following example:
const example = () => {
const [objects, setObjects] = useState([])
const asyncFunction = async() => {
// This will trigger the API and assume it takes around 10 seconds to run
let result = api.fetchObjects().then((result) => {
// Here, setObjects will be called with the value it had at the moment the function started executing, not the actual value
setObjects(result)
}
}
}
My question is, what is the best way to do setObjects(result) and use the updated state? Let's say that the user can add objects to that state during those 10 seconds by different means in the app.
I have found a solution using useEffect, like this:
// Instead of setObjects(result)
const [updateObjects, setUpdateObjects] = useState(null)
setUpdateObjects(result)
useEffect(() => {
if (updateObjects !== null) {
setObjects(updateObjects)
setUpdateObjects(null)
}
CodePudding user response:
You should use a functional state update to access and update from the previous state.
Note
Unlike the
setState
method found in class components,useState
does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:
const [state, setState] = useState({}); setState(prevState => { // Object.assign would also work return {...prevState, ...updatedValues}; });
Using Promise-chain
const asyncFunction = () => {
api.fetchObjects()
.then((result) => {
setObjects(objects => [
...objects, // <-- shallow copy previous state array
result, // <-- append new state
]);
});
}
or using async/await
const asyncFunction = async () => {
const result = await api.fetchObjects();
setObjects(objects => [
...objects, // <-- shallow copy previous state array
result, // <-- append new state
]);
}
Depending on the actual state shape and result
value your actual state update function may look a little different depending on your specific needs.