我正在尝试进行一些表单验证。我的表单中有两个受控元素:消息文本框和收件人文本框。因此,我有state.message
(字符串)和state.recipients
(数组)来控制一些文本框(当您在文本框中键入时,这些值state
更改)。状态工作正常。也就是说,当我在消息文本框中输入时,state.messages
会更新。当我在收件人框中输入时,state.recipients
会更新。invalid
是用useState
钩子定义的,如下所示:
const [invalid, setInvalid] = useState({
message: false,
recipients: false,
})
我希望invalid.messages
在state.messages
为空时true
,当state.recipients
为空时invalid.recipients
为真。这是我的验证代码,我遇到了一些麻烦:
if (state.recipients.length === 0) {
setInvalid({
...invalid,
recipients: true,
});
} else {
setInvalid({
...invalid,
recipients: false,
});
}
if (state.message === '') {
setInvalid({
...invalid,
message: true,
});
} else {
setInvalid({
...invalid,
message: false,
});
}
不过,我的条件是有效的。 当收件人文本框为空时,state.recipients.length
确实等于0
,当邮件文本框为空时,state.message
确实''
。现在,有趣的是,当表单的两个元素都为空时(即收件人和邮件都是空的),invalid
等于
{
recipients: false,
message: true
}
这非常奇怪,因为我没有看到我用来改变状态的逻辑有任何缺陷。更奇怪的部分是,当我翻转此验证逻辑中的 if 语句时(即,我首先检查消息状态,然后检查收件人状态),然后发生相反的情况:状态如下所示:
{
recipients: true,
message: false
}
我不知道为什么会这样,所以你能指出我的逻辑中的缺陷吗?
编辑:文本框的一些事件处理程序代码: 对于消息文本框:onChange={(e) => { setState({ ...state, message: e.target.value }); }}
对于收件人文本框(有意覆盖state.recipients
中的第一个元素):
onChange={(e, val) => setState({
...state,
recipients: val,
})}
但是这段代码真的不是问题,因为状态得到了正确处理,并且在应该为空的时候它是空的。
状态更新是异步的,因此当调用setInvalid
并使用...invalid
添加以前的状态时,两个更新都使用相同的旧状态。
换句话说,当调用您粘贴的代码时,要执行的第一个setInvalid
在第二个开始执行并使用...invalid
拉入状态之前不会完成状态更新。
因此,只有messaged
才能正确设置。
您可以通过使两个变量单独的状态对象来解决此问题。
const [invalidRecipiants, setInvalidRecipiants] = useState(true);
const [invalidMessages, setInvalidMessages] = useState(true);