I have below code :
import React,{useState} from 'react'
const iState ={
Name : '',
Email :'',
Salary :0,
Error:{
EName:'*',
EEmail:'*',
ESalary:'*'
}
}
function ReactForm() {
const [state, setstate] = useState(iState);
function validationHandler(e)
{
switch (e.target.name) {
case 'txtName':
console.log(e.target.value);
if(e.target.value=='')
{
console.log('inside condition')
setstate({state.Error, EName:'Value Cannot be blank'})
console.log(state);
}
else
{
console.log('inside else condition')
setstate({state, EName:''})
}
setstate({state, Name:e.target.value})
break;
case 'txtEmail':
setstate({state, Email:e.target.value})
break;
case 'txtSalary':
setstate({state, Salary:e.target.value})
break;
default:
break;
}
console.log(state);
}
return (
<div>
Name : <input name="txtName" type="text" onChange={(e)=>validationHandler(e)}></input>
<label> {state.Error.EName==undefined ? '*':state.Error.EName} </label>
<br></br>
Email : <input name="txtEmail" type="text" onChange={(e)=>validationHandler(e)}></input>
<br></br>
Salary : <input name="txtSalary" type="text" onChange={(e)=>validationHandler(e)}></input>
<br></br>
<button onClick={validationHandler}>Validate Us</button>
</div>
)
}
export default ReactForm
In this, iState has Error portion nested within –
const iState ={
Name : '',
Email :'',
Salary :0,
Error:{
EName:'*',
EEmail:'*',
ESalary:'*'
}
}
When I am trying to update the nested state of Error , its not getting updated –
if(e.target.value=='')
{
console.log('inside condition')
setstate({state.Error, EName:'Value Cannot be blank'})
console.log(state);
}
else
{
console.log('inside else condition')
setstate({state, EName:''})
}
I can see it entering within else block , but not updating the state.
I also tried with – setstate({...state.Error, EName:''})
EDIT 1 :
if(e.target.value=='')
{
console.log('inside condition')
setstate({ state, Error: { state.Error, Ename: 'Value Cannot be blank' }})
console.log(state);
}
else
{
console.log('inside else condition')
setstate({ state, Error: { state.Error, Ename: 'Value Cannot be blank' }})
}
Setting state changed –setstate({ ...state, Error: { ...state.Error, Ename: 'Value Cannot be blank' }})
Still state not getting updated –
Advertisement
Answer
Unlike this.setState
in class components, state setter function returned by the useState
hook does not merges the old state with the new state – you need to do it yourself. Not doing this will overwrite the existing state.
Currently you are overwriting the existing state. Correct way to update the state is shown below:
This
setstate({state.Error, EName:'Value Cannot be blank'})
should be
setstate({ state, Error: { state.Error, Ename: 'Value Cannot be blank' } })
Explanation of why this works:
First you spread the top level state object in the newly created object passed to setState
. After that you add Error
key and its value is another object in which you spread state.Error
. Finally, you add a Ename
key in the nested object and set its value.
Above steps re-create a new object with the similar structure as the initial state object.
Similarly this
setstate({state, EName:''})
should be
setstate({state, Error: { state.Error, EName:'' } })
Edit
Please note that state is updated asynchronously and it is constant within a particular render of a component.
This means that logging the state immediately after calling the state setter function will log the old state. Component can only see the updated state after it has re-rendered.
To log the updated state, use the useEffect
hook as shown below:
useEffect(() => {
console.log(state);
}, [state]);
This will log the updated state because it will execute:
- after the initial render
- every time component re-renders as a result of
state
update.