哈Ha 我向您介绍Kristofer Selbekk撰写的文章“在2020年在React中创建表单”的翻译
输入栏 文字区域。单选按钮和复选框。以下是我们作为开发人员与用户进行交互的一些要点。我们将它们放置在网站上,用户将其填写,如果幸运的话,完成的表格就不会出现验证错误。表单处理是大量Web应用程序不可或缺的一部分,这是React最好的事情之一。您拥有创建和处理表格的巨大自由。但是有更好的方法吗?请注意,在所有这些示例中,我们将创建一个包含电子邮件和密码字段的登录表单,但是这些方法可用于大多数类型的表单。记住良好形式的规则
尽管这与所讨论的主题没有直接关系,但我想确保您没有忘记使您的表单对所有人都可以理解。在输入字段中添加标签,为输入无效的情况设置正确的aria属性,并在语义上正确地构造内容。这使得用户和开发人员都可以轻松使用表单。使用状态挂钩处理表单
首先,让我们看看我通常如何使用表单状态。我将所有字段另存为单独的状态元素,并分别更新它们,如下所示:function LoginForm() {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
api.login(email, password);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor='email'>Email</label>
<input type='email' id='email' value={email} onChange={(e) => setEmail(e.target.value)} />
</div>
<div>
<label htmlFor='password'>Password</label>
<input type='password' id='password' value={password} onChange={(e) => setPassword(e.target.value)} />
</div>
</form>
);
}
首先,我创建状态的两个独立部分-用户名和密码。然后将这两个变量传送到相应的输入字段,以确定该字段的值。每当字段中的某些内容发生更改时,我们一定会更新状态值,从而导致应用程序重绘。这种表单处理在大多数情况下都可以正常工作,并且简单易用和易于理解。但是,每次编写这样的构造都是很乏味的。创建一个自定义钩子
让我们做一些重构并创建我们自己的钩子,这将稍微改善我们的代码:const useFormField = (initialValue: string = '') => {
const [value, setValue] = React.useState(initialValue);
const onChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value), []);
return { value, onChange };
};
export function LoginForm() {
const emailField = useFormField();
const passwordField = useFormField();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
api.login(emailField.value, passwordField.value);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor='email'>Email</label>
<input type='email' id='email' {...emailField} />
</div>
<div>
<label htmlFor='password'>Password</label>
<input type='password' id='password' {...passwordField} />
</div>
</form>
);
}
我们创建一个自定义useFormField钩子,该钩子为我们创建一个onChange事件处理程序,并将该值存储在表单状态中。在这种情况下,我们可以将钩子与所有表单字段一起使用。处理大量字段
这种方法的缺点是,随着表单的增长,它无法很好地扩展。对于诸如登录之类的小型表单,这可能很好,但是在创建用户个人资料表单时,您可能需要请求很多信息!我们应该一次又一次地调用钩子吗?每当遇到类似情况时,我都会编写一个自定义钩子,将所有表单存储在一个大片段中。它可能看起来像这样:export function LoginForm() {
const { formFields, createChangeHandler } = useFormFields({
email: '',
password: '',
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
api.login(formFields.email, formFields.password);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor='email'>Email</label>
<input type='email' id='email' value={formFields.email} onChange={createChangeHandler('email')} />
</div>
<div>
<label htmlFor='password'>Password</label>
<input type='password' id='password' value={formFields.password} onChange={createChangeHandler('password')} />
</div>
</form>
);
}
使用useFormFields挂钩,我们可以继续添加字段,而不会增加组件的复杂性。我们可以在一个地方访问所有表单状态,我们的代码看起来简洁明了。当然,在某些情况下,您可能需要使用setState,但是对于大多数形式,上述技术都很好。替代方法
因此,状态处理可以正常工作,并且在大多数情况下,这是React中的首选方法。但是您知道还有另一种方法吗?事实证明,浏览器默认情况下会处理表单的内部状态,我们可以使用它来简化代码!这是相同的表单,但是允许浏览器处理表单的状态:export function LoginForm() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
api.login(formData.get('email'), formData.get('password'));
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
name="email"
/>
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
name="password"
/>
</div>
<button>Log in</button>
</form>
);
}
看看有多容易!没有使用单个钩子,没有初始值设置,没有onChange处理程序。最好的部分是代码仍然可以像以前一样工作-但是如何?您可能已经注意到,我们在handleSubmit函数中所做的操作有些不同。我们使用称为FormData的内置浏览器API。 FormData是一种从我们的输入字段获取值的便捷(且得到良好支持)的方法!我们通过Submit事件的target属性获得到DOM中表单的链接,并创建FormData类的新实例。现在,我们可以通过调用formData.get(“输入字段名称”)来通过其名称属性获取所有字段。这样,您就无需显式处理表单的状态。如果您需要默认值(例如,如果您从数据库或本地存储中更改初始字段值),React为此提供了一个方便的defaultValue选项。何时使用每种方法
由于表单是大多数Web应用程序不可或缺的一部分,因此了解如何处理它们很重要。 React为您提供了许多方法来做到这一点。对于不需要严格验证(或可以依赖HTML5表单验证控件)的简单表单,我建议您仅使用DOM默认提供给我们的内置状态处理。有很多事情是您无法做的(例如,以编程方式更改输入值或实时检查),但是在最简单的情况下(例如,如上所述的搜索字段或登录字段),您可能会发现它很适合我们使用浏览器API的替代方法。当您执行自定义检查或在提交表单之前需要访问某些表单数据时,需要使用受控组件来显式处理状态。您可以使用常规的useStateHooks或创建自定义钩子来简化代码。值得注意的是,在大多数情况下,React开发人员建议使用受控组件(明确处理组件的状态),因为这种方法将来会给您带来更大的灵活性。在我看来,开发人员常常为了灵活性而牺牲了简单性,而他们通常并不需要这种灵活性。无论您决定使用哪种方法,React表单处理都从未像现在这样简单。您可以让浏览器处理简单表单,同时在情况需要时显式处理表单状态。希望以上方法对您有所帮助,并通过减少代码中的行数来帮助您解决问题。