ReactJs:嵌套状态未更新

时间:2021-06-04 05:53:23

标签: javascript reactjs react-hooks

我有以下代码:

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

在这里,iState 中嵌套了 Error 部分 -

const iState ={
        Name : '',
        Email :'',
        Salary :0,
        Error:{
            EName:'*',
            EEmail:'*',
            ESalary:'*'
        }    
    }

当我尝试更新 Error 的嵌套状态时,它没有得到更新 -

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:''})
                    }

我可以看到它进入 else 块,但没有更新状态。 我也试过 - setstate({...state.Error, EName:''})

编辑 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' }})
                }

设置状态已更改 -setstate({ ...state, Error: { ...state.Error, Ename: 'Value Cannot be blank' }})

仍然没有更新 -

enter image description here

4 个答案:

答案 0 :(得分:2)

您不应在设置新状态时直接使用之前的状态,因为状态更改是异步的。

setState((prevState)=>{...prevState, Error: { ...prevState.Error, EName:'Value Cannot be blank' }})

答案 1 :(得分:1)

你应该这样做

setstate({...state, Error: { ...state.Error, EName:'Value Cannot be blank' }})

答案 2 :(得分:1)

您必须使用传播当前状态并更新嵌套的 vaues

setState( previous => {...previous, Error: { ...previous.Error, EName:'Value Cannot be blank'} })

答案 3 :(得分:1)

与类组件中的 this.setState 不同,useState 钩子返回的状态 setter 函数不会将旧状态与新状态合并 - 您需要自己完成。不这样做将覆盖现有状态。

目前您正在覆盖现有状态。更新状态的正确方法如下所示:

这个

setstate({...state.Error, EName:'Value Cannot be blank'})

应该

setstate({ ...state, Error: { ...state.Error, Ename: 'Value Cannot be blank' } })

解释为什么会这样:

首先,您在传递给 setState 的新创建的对象中传播顶级状态对象。之后,您添加 Error 键,其值是另一个对象,您可以在其中扩展 state.Error。最后,在嵌套对象中添加 Ename 键并设置其值。

以上步骤重新创建了一个与初始状态对象结构相似的新对象。

同样如此

setstate({...state, EName:''})

应该

setstate({...state, Error: { ...state.Error, EName:'' } })

编辑

请注意,状态是异步更新的,并且在组件的特定渲染中保持不变。

这意味着在调用状态设置器函数后立即记录状态将记录旧状态。组件只能看到更新的状态在它重新渲染之后

要记录更新的状态,请使用 useEffect 钩子,如下所示:

useEffect(() => {
  console.log(state);
}, [state]);

这将记录更新的状态,因为它将执行:

  • 在初始渲染之后
  • 每次由于 state 更新而重新渲染组件。
相关问题