'State resets when values change in an object, only when I populate from another source
What I'm trying to do is the following:
- I want to select a single card view and edit it
- After editing it, I would like to save the changes
Please look at video I've upload for reference and could please explain what's going on, why is this happening. Is there a better way to do this without writing t0o much code as the state has a huge variable list and writing each variable will be time consuming.
This is my default useState where all values will be stored temporarily:
const [business, setBusiness] = useState<Partial<BusinessInterface>>({});
And the function to populate the state above is as follows:
const editHandler = async (e: any) => {
let editBusiness = await businessArray.businesses?.find(x =>
x.businessId?.equals(e),
);
console.log(e);
if (editBusiness) {
setBusiness(editBusiness);
setEditBusiness(true);
setModal(true);
}
}
However, the moment I start entering values, my state will clear the old state plus my change functions are all correct. please take a look at registrationNumberHandler
const registrationNumberHandler = (
e: NativeSyntheticEvent<TextInputChangeEventData>,
) => {
let value = e.nativeEvent.text;
setBusiness({...business, registrationNumber: value});
}
But however, when I change editHandler to as follows, it will work and my state will not change or clear the value when I edit a certain text field.
const editHandler = async (e: any) => {
let editBusiness = await businessArray.businesses?.find(x =>
x.businessId?.equals(e),
);
if (editBusiness) {
setBusiness({...business, name: editBusiness.name, registrationNumber: editBusiness.registrationNumber); // a short example, when text fields changes state will retain its values
setEditBusiness(true);
setModal(true);
}
}
Solution 1:[1]
I'm not sure in what scope your business variable is, but I think you're probably getting a stale state when you're trying to update it. You usually would want to use the callback version of the setState function.
setBusiness((prevValues) => ({...prevValues, registrationNumber: value}));
Solution 2:[2]
let editBusiness = await businessArray.businesses?.find(x =>
x.businessId?.equals(e),
);
console.log(e);
if (editBusiness) {
setBusiness(editBusiness);
Here you are passing editBusiness to setBusiness as a reference. So, editBusiness is also referring to the same object in businessArray. And now when you modify anything, it will modify the mainArray as well as both are pointing to the same memory location.
setBusiness({...business, name: editBusiness.name, registrationNumber: editBusiness.registrationNumber);
Here, instead of passing reference you have created a new object which is not pointing to your businessArray and hence it doesn't modify your previous state on edit.
Solution 3:[3]
Your components are probably running with an outdated scope.
A component will only know about changes to business after it re-renders.
await pushes the execution of your code to the back of the queue which may cause the scope of your component to be even more outdated.
Solution: setState (or setBusiness in your case) has a way of giving you the most recent state.
Take a look at the rewritten function below. It should solve your problems ??
const registrationNumberHandler = (
e: NativeSyntheticEvent<TextInputChangeEventData>
) => {
let value = e.nativeEvent.text
setBusiness(previousState => ({
...previousState,
registrationNumber: value
}))
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | diedu |
| Solution 2 | |
| Solution 3 | Marius Brataas |

