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.