React 表单 useState 对象无法按我的意愿工作
Posted
技术标签:
【中文标题】React 表单 useState 对象无法按我的意愿工作【英文标题】:React form useState object doesn't work as I want 【发布时间】:2022-01-24 00:44:00 【问题描述】:我的 React 应用程序有问题。我有一个带有两个输入的表单,当我提交带有空输入的表单时,它应该在每个输入中呈现一条错误消息。问题是它没有显示第一个输入。如何修复它以显示每个错误?实现在useForm.js
。
FormUI 图片:
我的代码:
Form.js
const Form = () =>
const formLogin = () =>
console.log("Callback function when form is submitted!");
console.log("Form Values ", values);
const handleChange, values, errors, handleSubmit = useForm(formLogin);
return (
<Wrapper>
<form onSubmit=handleSubmit>
<div className="govgr-form-group gap-bottom">
<label className="govgr-label govgr-!-font-weight-bold" htmlFor="code">Code*</label>
errors.code && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>errors.code</p>
<input className=`govgr-input govgr-!-width-three-quarter $errors.code ? 'govgr-error-input' : ''` id="code" name="code" type="text" onChange=handleChange />
</div>
<fieldset>
<div className="govgr-form-group">
<label className="govgr-label govgr-!-font-weight-bold" htmlFor="first">Name*</label>
errors.first && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>errors.first</p>
<input className=`govgr-input govgr-!-width-three-quarter $errors.first ? 'govgr-error-input' : ''` id="first" name="first" type="text" onChange=handleChange />
</div>
</fieldset>
<button type="submit" className="govgr-btn govgr-btn-primary btn-center">Save</button>
</form>
</Wrapper>
);
;
export default Form;
useForm.js
:
const useForm = (callback) =>
const [values, setValues] = useState();
const [errors, setErrors] = useState();
const validate = (event, name, value) =>
event.persist();
switch (name)
case "code":
if (value.trim() === "" || value.trim() === null)
setErrors(
...errors,
code: "Code is required",
);
else
let newObj = omit(errors, "code");
setErrors(newObj);
break;
case "first":
if (value.trim() === "" || value.trim() === null)
setErrors(
...errors,
first: "Name is required",
);
else
let newObj = omit(errors, "first");
setErrors(newObj);
break;
default:
break;
;
const handleChange = (event) =>
event.persist();
let name = event.target.name;
let val = event.target.value;
validate(event, name, val);
setValues(
...values,
[name]: val,
);
;
const handleSubmit = (event) =>
if (event) event.preventDefault();
if (
Object.keys(errors).length === 0 &&
Object.keys(values).length !== 0 &&
values.code &&
values.first
)
callback();
else
if (!values.code)
setErrors(
...errors,
code: "Code is required.",
);
if (!values.first)
setErrors(
...errors,
first: "Name is required.",
);
;
return
values,
errors,
handleChange,
handleSubmit
;
;
export default useForm;
【问题讨论】:
此代码中不需要event.persist()
。这仅适用于异步处理程序。此外,您复制了验证码。这些都不会导致您的错误,但无论如何您都应该注意它们。
您不应该在setErrors
调用中使用errors
。您应该改用此构造:setErrors(e => (...e, code: "Code is required"))
。尝试删除错误时同样适用:使用setErrors(e => e.filter(e.hasOwnProperty('code'))
,或类似的东西。
我不认为你可以在这里使用 switch 语句,默认情况下 switch 语句返回许多选项之一。因此,您只会返回一个错误,您可以在此处阅读更多信息 -> w3schools.com/js/js_switch.asp 我也认为这段代码对于您想要实现的目标来说过于复杂,也许需要重新编写。
@snazzyy - validate/switch 是从 onchange 事件中调用的,它只在单个字段中被调用,所以它是正确的。我同意这段代码太复杂了。
你是对的@SoftwareEngineer
【参考方案1】:
您可以通过只有一个验证例程来简化您的代码。您可以通过使用框架传递给setState
的当前状态来修复您提到的错误,一次只有一个错误。这个结构是
setState(e => /* whatever you want to return relative to e */);
最终,您看到的错误是因为组件及其代码在每次状态更改后都会重新呈现(但出于性能原因它们是批处理的),因此您的代码仅在以下情况下看到旧版本的状态你直接访问它。如果您在更改时想要实际的当前状态,最好让框架直接将其传递给 change-state 函数。如果您始终遵循这种模式,那么您很少会遇到 react 状态模型的任何问题。
然而,难题不在于这些。难题是您消除错误的方式。首先,从 UI 的角度来看,仅在编辑字段时将其显示为错误有点不一致,因为表单在首次显示时是错误的。但是,忽略这一点,潜在的技术问题是从对象中删除属性。通常,当我们需要这样做时,我们会使用数组而不是对象,或者我们会使用下划线的omit
函数。我在您的代码中看到您调用了一个名为omit
的函数,但您没有解释它是什么。不过,在您的情况下,这可以通过从不删除该属性来轻松解决。相反,将每个作为具有有效标志的对象。这将允许您完全删除 switch 语句。
你也可以更进一步,在那里滚动值,为每个字段创建一个完整的单一状态,但我不会在这里演示。
我还没有测试过这个,所以这里可能有一两个错字。
const useForm = (callback) =>
const [values, setValues] = useState(code: '', first: '');
const [errors, setErrors] = useState(first: message: "Name is required", valid: true, code: message: "Code is required", valid: true);
const isEmpty = val => val.trim() === "" || val.trim() === null);
const validate = (name, val) =>
setErrors(e => (...e, [name]: ...e[name], valid: isEmpty(val)))
return errors[name].valid;
;
const handleChange = (event) =>
let name = event.target.name;
let val = event.target.value;
setValues(...values, [name]: val);
validate(name, val);
;
const handleSubmit = event =>
if (event) event.preventDefault();
const valid = validate('code', values.code) && validate('first', values.first);
if ( valid )
callback();
;
return
values,
errors,
handleChange,
handleSubmit
;
;
export default useForm;
而且,您必须稍微更改您的 HTML 模板:
!errors.first.valid && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>errors.first.message</p>
我意识到这个新的validate
函数与您拥有的功能大相径庭,但根据您自己的代码,我认为您可以处理它。基本上,它只是使用解构和变量属性访问器。这看起来在您的理解能力范围内,但如果其中任何一个令人困惑或实际上不起作用,请随时提出更多问题:)
【讨论】:
以上是关于React 表单 useState 对象无法按我的意愿工作的主要内容,如果未能解决你的问题,请参考以下文章
使用 Axios 将对象从 React.js 发布到 PHP
React.js useState hook 导致过多的重新渲染并且无法更新我的状态
我的 React useState 不能立即在 useEffect 中设置对象。有人能帮我吗?