const [obj, setObj] = useState{
id1: false,
id2: false,
...
})
const someFunc = async(id)=> {
setObj({...obj, [id]: true})
await longApiCall()
setObj({...obj, [id]: false})
}
This function gets called a couple times (or more), and this should set both to true then both to false, but they complete at close to the same time. Because setting state is asynchronous, each set state only flips one to false because the second one overwrites it back to true.
What's the best way to ensure the state object always gets the correct updates? I know that I can use a ref or directly set the property on the obj without using the state setter, but I want to maintain the behavior that this state change causes a rerender.
// after calls are finished
obj = {
id1: true,
id2: false
}
//desired outcome
obj = {
id1: false,
id2: false
}
Use the function version of set state instead. React will pass you in the latest value of the state, and you can calculate the new state from that:
const someFunc = async(id)=> {
setObj(prev => {
return {...prev, [id]: true};
});
await longApiCall();
setObj(prev => {
return {...prev, [id]: false};
});
}
This is the cleanest solution I could come up with.
const objMimic = useRef({})
const someFunc = async(id)=> {
objMimic.current[id] = true
setObj({...obj, [id]: true})
await longApiCall()
objMimic.current[id] = false
setObj({...objMimic.current})
}