I have a form with many input elements and a button which goes on next page. Before moving forward it validates all the inputs in such a way that if any it is empty then the corresponding label should be red. For that I made a class text-red in css and if any value is empty it sets it to that class.
I decided to store that value in object itself for every key.
I have an object like this (Couldn’t post the actual code)
const [data,setData] = useState({
key1:{value:'',valueTextClass:'', formula:'', formulaInputClass:''},
key2:{value:'',valueTextClass:'', formula:'', formulaInputClass:''},
key3:{value:'',valueTextClass:'', formula:'', formulaInputClass:''}
})
When I click on the button, it calls a validation function and it validates every field one by one.
This is the block of code I have written.
const validate = (key) => {
Object.keys(data).forEach(key => {
if(data[key].value == '')
setData(prev => (...prev, [key]:({...data[key], valueTextClass:'text-red' })));
if(data[key].formula == '')
setData(prev => (...prev, [key]:({...data[key], formulaInputClass:'text-red' })))
})
}
When both values are empty then only the formula label sets to red, value label remains the same.
I have tried a lot to figure out but I ended with nothing.
2
Answers
The problem is related to the multiple calls to
setData
. Set state actions are async and therefore you have to call it one time to solve the issue.In this way you build a single object that then updates the state correctly in only 1 call.
In order to update all values asynchronously you should wrap the full update functionality in
setData
and not just each individual statement. Below is a solution similar to yours that does just that.Some things to note:
key
tovalidate
is never used so it can be removed.newData = { ...prev }
, but instead modifyprev
directly, React won’t know about the changes and we will get bugs.data
andprev
will likely be the same inside the scope of the update function passed tosetData
. However, this is not guaranteed and we should only useprev
since it is guaranteed to contain the latest changes.Below is how I would have solved the issue, with a functional approach and by leveraging
Object.entries
.