Javascript 从React钩子读取状态
我有以下代码Javascript 从React钩子读取状态,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我有以下代码 const initialState = { values: { email: '', password: '' }, touched: { email: false, password: false }, errors: false, isValid: false, isLoading: false, submitError: null }; func
const initialState = {
values: {
email: '',
password: ''
},
touched: {
email: false,
password: false
},
errors: false,
isValid: false,
isLoading: false,
submitError: null
};
function SignIn(props) {
const [state, setState] = useState(initialState);
useEffect(() => {
console.log(state);
});
const handleFieldChange = (field, value) => {
const newState = state;
newState.submitError = null;
newState.touched[field] = true;
newState.values[field] = value;
newState.errors = true; // set to true just for test
setState(newState);
};
const showEmailError = state.errors.email;
return (
<div>
<TextField
className={classes.textField}
label="Email address"
name="email"
onChange={event => handleFieldChange('email', event.target.value)}
type="text"
value={state.email}
variant="outlined"
/>
{showEmailError && (
<Typography
className={classes.fieldError}
variant="body2"
>
{state.errors.email[0]}
</Typography>
)}
</div>
)
}
const initialState={
价值观:{
电子邮件:“”,
密码:“”
},
感动:{
电子邮件:false,
密码:false
},
错误:错误,
isValid:false,
孤岛加载:false,
错误:空
};
功能标志(道具){
常量[状态,设置状态]=使用状态(初始状态);
useffect(()=>{
console.log(状态);
});
常量handleFieldChange=(字段,值)=>{
const newState=状态;
newState.submitor=null;
newState.toucted[field]=true;
newState.values[字段]=值;
newState.errors=true;//仅为测试设置为true
设置状态(newState);
};
const showmailerror=state.errors.email;
返回(
handleFieldChange('email',event.target.value)}
type=“text”
值={state.email}
variant=“概述”
/>
{showmailerror&&(
{state.errors.email[0]}
)}
)
}
我遇到的问题是,当执行
handFieldChange
时,不会出现电子邮件错误。好像我没有在我的返回声明中得到最新的状态更改。我做错了什么?首先,要存储大对象,如本例中所示,请使用useReducer
而不是useState
通过键入constnewstate=state代码>您正在分配相同的对象,因此您将使用仍然相同的对象。使用constnewstate={…state}
或类似的东西
让我们看看下面:
const showEmailError = state.errors.email;
[...]
{state.errors.email[0]}
您的state.errors属性是布尔属性,因此它没有任何嵌套对象
在useffect中,您需要传递依赖项数组,该数组将被跟踪并在任何更改时调用函数。要仅调用一次,请传递空数组:
useEffect(() => {
console.log(state);
}, []);
如果要记录每个状态的更改,请将状态作为依赖项传递。setState
认为没有任何更改,因为每次传递的都是相同的状态
对象。在每次更新时创建一个新对象:
constnewstate={…state};
我在评论中给了你一个提示,但你似乎忽略了它。您不应该直接修改state对象,因为当您调用setState时,React会将其与原始state对象引用进行比较(感谢Ross在注释中指出)。由于您已经对其进行了变异,并且React没有发现任何更改的属性,因此不会更新组件,因此不会调用useffect
hook。在工作之前创建对状态对象的新引用。以下是您需要做的:
替换
const newState = state;
与
FYI doconst newState=state
然后使用newState
,您仍在使用旧的状态对象是的,我知道。但这不是这里的问题。这正是问题所在@bryan只是提醒一下,你useffect
在这里没有任何作用,只是做console.log(state)代码>将显示您的状态更改。一旦您修复了状态更改,当然……)@基思:是的,我知道。为了测试组件是否被重新渲染,我添加了它,但因为我使用的是同一个对象,所以它不是:PAh,我忘了删除它。当我将state.errors.email替换为随机文本时,不会显示任何内容。我的问题是,useEffect只记录一次,即使我没有向它传递任何参数。是的,如果要记录每个状态的更改,您需要将状态作为依赖项传递给useEffect,然后每次更改都将被记录。这可能会起作用,但当OP从回调中删除error=true
时,浅层克隆(以及此方法)将失败,因为您的代码仍在处理同一对象的属性。这样的分解会创建一个浅层克隆。useState
使用对象引用来确定是否重新渲染。为什么需要深度克隆?因为在问题中,OP修改嵌套属性(obj.prop1.prop2…
,当您执行像useState
这样的浅层克隆时,这些属性不会被克隆,它们只与传递给它的对象有关,如果引用发生更改,它将返回一个更新的值。在OP的情况下,整个组件将重新渲染并拾取对嵌套对象的更改。这里不需要深度克隆。@mehuimpt:哦,对不起。是的,ofc!我正在将类组件转换为钩子,但错过了这个。。。。非常感谢。应该提到的是,解构
不是深度克隆,可能会导致意外行为。另外,在考虑性能时,应该尝试使用自己的/library深度克隆函数,如lodash。.deepClone
@DennisVash,我是说递归解构。谢谢你指出这一点out@mehulmpt:所以我应该避免像这样进行破坏:{…state}?{…state}如果您只有一个级别的内容需要更改(如state.prop1或state.prop2),那么如果您想要更改state.prop1.nestedprop1
,那么您必须执行类似const newstate={…state,prop1:{…state.prop1}}
浅层克隆state.prop1
,或者只要它是JSON友好的,您就可以将其字符串化并再次解析为JSON(即,没有函数或循环依赖项,在大多数情况下,您不需要担心状态对象中的这一点)@Bryan
const newState = { ...state }