简单的前端表单验证-前端表单验证插件
作者| Nathan Sebhastian 翻译 | 顾军 编辑 | 尤涅
使用 React 构建表单涉及创建状态作为用户数据的容器,并创建道具作为控制状态如何根据用户输入更新的方式。 验证可以在用户输入间隔之间完成,提交表单时将执行任何提交功能。
这是一个基本的 React 表单示例,没有其他库,并且具有最少的 Bootstrap 样式:
代码地址:
在下面的例子中,我们首先在构造方法中初始化必要的状态值。 因为这里我们需要两个必要的输入,email 和 password,所以我们对它们的输入值、正确性和错误都初始化了对应的状态:
constructor(props) {
super(props);
this.state = {
formValues: {
email: "",
password: ""
},
formErrors: {
email: "",
password: ""
},
formValidity: {
email: false,
password: false
},
isSubmitting: false
};
}
接下来简单的前端表单验证,我们为表单创建渲染方法,其中输入的值是从状态中获取的:
render() {
const { formValues, formErrors, isSubmitting } = this.state;
return (
Login Form
);
}
现在我们需要编写 handleChange 方法来根据用户输入更新状态:
handleChange = ({ target }) => {
const { formValues } = this.state;
formValues[target.name] = target.value;
this.setState({ formValues });
this.handleValidation(target);
};
每当更新状态值时,我们都会根据用户的输入执行验证方法。 这是我们的 handleValidation 方法:
handleValidation = target => {
const { name, value } = target;
const fieldValidationErrors = this.state.formErrors;
const validity = this.state.formValidity;
const isEmail = name === "email";
const isPassword = name === "password";
const emailTest = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
validity[name] = value.length > 0;
fieldValidationErrors[name] = validity[name]
? ""
: `${name} is required and cannot be empty`;
if (validity[name]) {
if (isEmail) {
validity[name] = emailTest.test(value);
fieldValidationErrors[name] = validity[name]
? ""
: `${name} should be a valid email address`;
}
if (isPassword) {
validity[name] = value.length >= 3;
fieldValidationErrors[name] = validity[name]
? ""
: `${name} should be 3 characters minimum`;
}
}
this.setState({
formErrors: fieldValidationErrors,
formValidity: validity
});
};
这个基本表单的最后一步是提交过程所需的 handleSubmit 方法。 我们首先检查 formValidity 中的值,如果它的值为 false,我们再次运行验证方法而不提交表单。
handleSubmit = event => {
event.preventDefault();
this.setState({ isSubmitting: true });
const { formValues, formValidity } = this.state;
if (Object.values(formValidity).every(Boolean)) {
alert("Form is validated! Submitting the form...");
this.setState({ isSubmitting: false });
} else {
for (let key in formValues) {
let target = {
name: key,
value: formValues[key]
};
this.handleValidation(target);
}
this.setState({ isSubmitting: false });
}
};
该表格现在可以使用了。 React 只为您的应用程序提供视图层,这意味着它只提供制作表单组件的基本要素。 组件、状态和道具就像拼图的碎片,您必须将它们组合在一起才能构建可用的表单。
如您所见,只有两个字符输入字段的表单需要这么多代码。 试想一下,对于一个有十个或更多输入的表单,你需要维护多少个状态值。 难以想象!
是的,用 React 制作表单并不好玩; 这是非常乏味和僵化的。 构建表单和创建验证方法是一项非常无趣的任务。 在每种形式中,您至少应执行以下操作:
为表单值、错误和正确性创建状态。
处理用户输入和更新状态。
创建验证函数。
处理提交。
要以本机 React 方式创建表单,您需要编写从构建状态到提交表单的过程的每个部分。 我做过无数 React 表单,每次我都发现构建表单的这一部分特别无聊和耗时。 幸运的是,我并不孤单。
初看 Formik
Jared Palmer 出于对构建 React 表单的失望而编写了 Formik 库。 他需要一种方法来标准化输入组件和表单提交流程。 Formik 将帮助您编写创建表单时最烦人的三个部分:
读取或写入表单状态的值。
验证和错误消息。
处理表单提交。
这是相同的形式,但这次使用 Formik:
代码地址:
这种新形式仅使用 Formik 库中的四个附加组件: 、 和 。 要释放 Formik 的力量,您可以将表单包装在一个组件中:
接下来让我们看看与 React 的原生方式相比,Formik 如何让构建表单变得更容易。
读取或写入表单状态的值
Formik 会在内部通过它的 initialValues 属性为用户输入创建相应的状态,所以你不需要在构造方法中自己初始化状态。
为了能够读取或写入 Formik 的内部状态,您可以使用组件而不是常规的 HTML 组件。 该组件将神奇地将 Formik 状态与输入值同步,因此您无需将 value 和 onChange 属性传递给组件:
initialValues={{ email: "", password: "" }}
onSubmit={({ setSubmitting }) => {
alert("Form is validated! Submitting the form...");
setSubmitting(false);
}}
>
{() => (
)}
使用 Formik,您不需要在构造函数方法中初始化状态,也不需要创建自己的 handleChange 方法。 这些都被 Formik 接管了。
验证和错误消息
当某些事件发生时,Formik 中的验证会自动执行。 所有常见的事件,包括用户输入、焦点改变、提交,你都不需要关心。 您需要做的就是将一个函数传递给 Formik 的 validate 属性。
我们来对比一下 Formik 的验证和原生 React 的验证:
// Formik validation code. Take values from Formik
validate={values => {
let errors = {};
if (values.email === "") {
errors.email = "Email is required";
} else if (!emailTest.test(values.email)) {
errors.email = "Invalid email address format";
}
if (values.password === "") {
errors.password = "Password is required";
} else if (values.password.length < 3) {
errors.password = "Password must be 3 characters at minimum";
}
return errors;
}}
// Vanilla React validation code. Take values given by handleChange
handleValidation = target => {
const { name, value } = target;
const fieldValidationErrors = this.state.formErrors;
const validity = this.state.formValidity;
const isEmail = name === "email";
const isPassword = name === "password";
const emailTest = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
validity[name] = value.length > 0;
fieldValidationErrors[name] = validity[name]
? ""
: `${name} is required and cannot be empty`;
if (validity[name]) {
if (isEmail) {
validity[name] = emailTest.test(value);
fieldValidationErrors[name] = validity[name]
? ""
: `${name} should be a valid email address`;
}
if (isPassword) {
validity[name] = value.length >= 3;
fieldValidationErrors[name] = validity[name]
? ""
: `${name} should be 3 characters minimum`;
}
}
this.setState({
formErrors: fieldValidationErrors,
formValidity: validity
});
};
准备好验证后,您现在需要输出错误消息。 Formik 组件将自动显示包含名称属性的组件的错误消息。 您可以通过 component 属性调整显示哪些 HTML 标签。 因为本例中的表单使用了 Bootstrap 样式,所以还需要添加一个 className 属性:
// Formik error message output
type="email"
name="email"
className={`form-control ${
touched.email && errors.email ? "is-invalid" : ""
}`}
/>
component="div"
name="email"
className="invalid-feedback"
/>
// Vanilla React error message output
type="email"
name="email"
className={`form-control ${
formErrors.email ? "is-invalid" : ""
}`}
placeholder="Enter email"
onChange={this.handleChange}
value={formValues.email}
/>
{formErrors.email}
报错信息相关的代码其实是一样的,但是相比原生的React,Formik的验证代码少了很多。 福米克,我们走!
前端人的成长离不开与优秀同行的交流。 你可以加入我们的“前端技术交流群”。 社区会经常讨论前端相关技术,分享免费学习资料。 我们还将邀请前端达人进行社群分享、直播、公开课等活动,冬天就在群里! 有兴趣欢迎加社区管理员微信GeekUni004,回复“前端群”申请入群。 是的让验证更容易
虽然您已经可以看到在验证过程中使用 Formik 的好处,但您可以通过使用对象模式验证器使该过程更容易。
对象架构验证器是一个蓝图,允许您定义 JavaScript 对象并确保对象的值在整个验证过程中与蓝图匹配。 这在验证表单数据时特别有用,因为它实际上是一个由 Formilk 的 values 属性持有的对象。
目前有这样一个库叫Yup,Formik的作者非常喜欢Yup简单的前端表单验证,所以引入了一个特殊的属性validationScheme来连接Yup和Formik。 该属性会自动将 Yup 的验证错误转换为一个友好的对象,其键匹配值并被触摸。
下面是 Formik 使用 Yup 作为其身份验证模式的示例。 注意如何从组件中删除 validate 属性:
代码地址:
通过使用 Yup 的对象模式验证器,您不再需要手动编写 if 条件判断。 您可以访问此 Github 目录以了解有关 Yup 的更多信息以及它可以执行的身份验证类型:
表单提交流程
Formik 的组件将自动运行您的验证方法,并在出现任何错误时取消提交过程。 常规元素要求您引入 onSubmit 属性,而 Formik 的包装器将运行您传递给组件的 onSubmit 属性的函数:
// Formik's submit code. Won't be executed if there are any errors.
onSubmit={({ setSubmitting }) => {
alert("Form is validated!");
setSubmitting(false);
}}
// Vanilla React submit code. Check on validity state then run validation manually.
handleSubmit = event => {
event.preventDefault();
this.setState({ isSubmitting: true });
const { formValues, formValidity } = this.state;
if (Object.values(formValidity).every(Boolean)) {
alert("Form is validated!");
this.setState({ isSubmitting: false });
} else {
for (let key in formValues) {
let target = {
name: key,
value: formValues[key]
};
this.handleValidation(target);
}
this.setState({ isSubmitting: false });
}
};
Formik 至少需要 4 行代码来完成提交,而且你不需要跟踪表单输入的正确性。 这真的很整洁!
那么 redux-form 呢?
当然,redux-form 很好用,但首先你需要使用 Redux。 如果你想使用 MobX 怎么办? 如果稍后出现更新更好的库并且您想使用它而不是 Redux 怎么办? 在这个前提下,你的 React 表单会不会在某种程度上影响你整个应用的数据流?
想一想:用户名文本输入框的值对全局应用有用吗? 如果不是,那么使用 Redux 来跟踪它的值就没有意义了。 甚至布道者丹阿布拉莫夫也说过同样的话。
redux-form 的另一个问题是你将表单的输入值存储在 Redux store 中。 这意味着每次按下一个键时,您的应用程序都会调用 Redux reducer 来更新文本字段的值。 这不是一个好主意。
我喜欢用 Formik 编写表单,但如果你更喜欢 redux-form,那也很好。
总结
构建表单不是 React 擅长的。 幸运的是,React 有一个开发人员社区,他们愿意帮助他人并简化编写代码的过程。
如果你需要在你的 React 应用中编写大量的表单,那么 Formik 绝对是你必备的开源库之一。 它将真正加快您的开发过程,并通过组件(例如 和 )抽象您的表单来减少样板代码。
原生 React 表单需要您定义自己的状态值和方法,而您只需将 props 传递给组件即可完成相同的操作:处理用户输入、验证输入并提交表单。
如果您想了解更多关于 Formik 的信息,可以在这里阅读作者自己的文档:
英文原文: