在使用React进行开发的时候,如果是简单的表单还好。如果遇到复杂的表单,比如分好几个步骤的表单,联动效果的字段,多层结构的字段等等,就需要一个好的框架的支持了。下面介绍一下:Formik

Formik官网:https://formik.org/
Formik GH:https://github.com/jaredpalmer/formik
Formik介绍
Formik是一个专门用于处理Form的React组件。通过Formik,可以管理表单中的数据,进行输入验证,错误提示,以及表单提交。其实上面提到的这些功能通过基本的React也能实现,只不过通过Formik,可以在可扩展性,性能,及实现时的难易度上做出很大的改进。
普通表单的实现
先来看一下基本表单的实现:
<form>
<label htmlFor='name'>Name</label>
<input type="text" id="name" name="name"/><br/>
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email"/><br/>
<label htmlFor="age">Age</label>
<input type="age" id="age" name="age"/><br/>
<button>Submit</button>
</form>
使用formik
安装formik
npm install formik
如何在React中使用Formik
基本使用:
import React from "react";
import { useFormik } from "formik";
export default function NormalForm() {
const initialValues = {
name: "",
email: "",
age: 18,
};
const onSubmit = values => {
console.log(values);
};
const validate = values => {
const errors = {
name: values.name? undefined: 'Name is required.',
email: /[\w-]+@([\w-]+\.)+[\w-]+/i.test(values.email)? undefined: 'Invalid email.',
age: (parseInt(values.age) > 0 && parseInt(values.age) < 100)? undefined: 'Age is invalid.',
}
console.log(errors);
return errors;
};
const formik = useFormik({
initialValues,
onSubmit,
validate
});
return (
<div>
<form onSubmit={formik.handleSubmit}>
<label htmlFor="name">Name</label>
<input
type="text"
id="name"
name="name"
onChange={formik.handleChange}
value={formik.values.name}
/>
{formik.touched.name && formik.errors.name? formik.errors.name: ''}
<br />
<label htmlFor="email">Email</label>
<input
type="text"
id="email"
name="email"
onChange={formik.handleChange}
value={formik.values.email}
/>
{formik.touched.email && formik.errors.email? formik.errors.email: ''}
<br />
<label htmlFor="age">Age</label>
<input
type="age"
id="age"
name="age"
onChange={formik.handleChange}
value={formik.values.age}
/>
{formik.touched.age && formik.errors.age? formik.errors.age: ''}
<br />
<button type="submit">Submit</button>
</form>
</div>
);
}
在使用Formik的时候,需要传递三个参数给useFormik:
- initialValues: 通过这里实现对表单字段的绑定
- onSubmit: 实现表单提交功能
- validate: 实现表单验证
更为复杂的验证规则
在构建较为复杂的表单时,可能一个属性值的合法性取决于另一个属性值。在这个时候,就可以使用以下的方法:
const validate = values => {
let errors = {};
if(!values.name) {
errors.name = 'Name is required.';
}
if(!/[\w-]+@([\w-]+\.)+[\w-]+/i.test(values.email)) {
errors.email = 'Invalid email.'
}
if(!(parseInt(values.age) > 0 && parseInt(values.age) < 100)) {
errors.age = 'Age is invalid.';
}
return errors;
};
使用yup进行验证
安装依赖库:
npm install yup
导入并使用:
import * as Yup from 'yup';
// ...
const validationSchema = Yup.object({
name: Yup.string().required('必填字段.'),
email: Yup.string().email('错误邮件地址').required('必填字段'),
age: Yup.number().required('必填字段')
});
const formik = useFormik({
initialValues,
onSubmit,
validationSchema
});
官网:https://github.com/jquense/yup#validation-tests
关于conditional validation的讨论:https://stackoverflow.com/questions/49394391/conditional-validation-in-yup
关于在yup中自定义验证规则的讨论:https://stackoverflow.com/questions/63769152/how-to-get-yup-to-perform-more-than-one-custom-validation
代码的优化
可以看到,在上面代码中,类似的代码在不断重复:
name="name"
onChange={formik.handleChange}
value={formik.values.name}
// ...
name="age"
onChange={formik.handleChange}
value={formik.values.age}
可以使用如下方式进行简化:
{...formik.getFieldProps('age')}
最终版本:
<input
type="age"
id="age"
name="age"
{...formik.getFieldProps('age')}
/>
关于visited field
设想有一个表单,要求对字段输入即时验证,并即可给出错误提示。假设有30个不同字段。那么设想一下,在刚加载表单的时候,所有字段都为空,可能都无法通过验证。这时肯定不能立刻显示这些字段值非法。否则会吓坏用户的。只有当用户输入了某个字段值之后并把光标切换到其他位置时,才需要进行验证。这时就需要使用Formik中的visited字段功能了。
其实,这些在Formik中都已经做好了,它们都已经被封装在formik.touched这个对象中了:
formik.touched.name
对于某个字段来说,需要增加onBlur处理函数:
<input
type="age"
id="age"
name="age"
onChange={formik.handleChange}
onBlur={formik.handleBlue}
value={formik.values.age}
/>
这样Formik就会维护touched对象的值,一旦某个字段已经被使用过的话,其值为true:
{
name: true
}