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

表单验证会在何时运行?
表单验证会在以下几种情况下被触发,进而更新formik.errors对象:
- 一旦输入字段中的值发生变化时
- 一旦表单字段失去输入焦点
- 表单提交时
如果想要当表单字段变化或失去输入焦点时取消表单验证,则可以:
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
validateOnChange={false}
validateOnBlur={false}
>
字段级验证规则
默认情况下,通过传递validationSchema或者validate属性给Formik组件来定义顶级验证规则。其实,还可以针对某个字段来定义字段级验证规则。
什么时候需要使用字段级验证呢?比如:在渲染一个字段的时候,需要调用一个API来获取数据才能渲染,获取完数据后才能进行验证,这是就需要使用字段级别验证了。
定义验证函数
const validateFeedback = value => value? undefined: 'Required';
在字段中使用验证函数
<label htmlFor="feedback">Feedback</label>
<Field
type="text"
id="feedback"
name="feedback"
validate={validateFeedback}
/>
<ErrorMessage name='feedback'/>
人工控制验证规则
使用顶级的formik对象
类似于Formik组件中的render props,在顶级Formik元素上也可以这样做:
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}>
{
formik => {
return (
<Form>
......
</Form>
)
}
}
</Formik>
当需要在整个Form级别做一些操作时,就可以使用formik这个对象了。
人工控制验证逻辑
<button type='button' onClick={() => formik.setTouched({
name: true,
age: true,
feedback: true
})}>访问所有字段</button>
<button type='button' onClick={() => formik.validateForm()}>验证表单</button>
<button type='button' onClick={() => formik.setFieldTouched('feedback')}>使用feedback字段</button>
<button type='button' onClick={() => formik.validateField('feedback')}>验证feedback字段</button>
在Formik中,只有当一些字段被使用过之后,才会显示验证失败后的信息。因此上面需要调用setFieldTouched/setTouched方法来声明某个字段已经被“访问“过了。
使用场景:在用户注册表单中,当用户输入用户名之后,需要调用API检查用户名是否已经存在,然后根据API返回结果显示用户名是否可用。
禁用提交按钮
应用场景:
- 当表单中有些字段非法时,需要禁用提交按钮
- 当表单正在提交过程中时,为了避免重复提交,需要禁用提交按钮
表单未通过验证时禁用提交按钮
在前面提到的Formik对象render props中,有一个属性:isValid,用来指示当前表单数据是否合法。
<button type='submit' disabled={ !formik.isValid }>提交</button>
目前有一个小问题,当表单被加载时,由于所有字段都未被访问,因此isValid的初始值为true,其实这个时候是不能提交表单的。
使用validateOnMount在表单加载初期禁用提交按钮
如果想要解决这个问题,第一种方法就是为Formik添加validateOnMount属性,这样在表单加载时就会进行验证:
<Formik
initValues={initValues}
...
validateOnMount>
...
</Formik>
但这种方式仅仅适用于简单表单,当表单过于复杂时,尤其是验证规则过于复杂时,这种方式并不适合。
使用formik.dirty属性
dirty属性反映出表单数据是否被更新。
<button type='submit' disabled={ !(formik.dirty && formik.isValid) }>提交</button>
但这种方式也有一个问题:当表单字段有初始值时,dirty的值就会为false,因此提交按钮将被禁用。
表单提交过程中禁用提交按钮
这时可以使用isSubmitting属性。
<button type='submit' disabled={formik.isSubmitting}>
在默认方式下,提交后formik.isSubmitting的值就会变为false, 同时提交按钮就会被禁用。这是因为Formik无法获取在提交时调用的API何时会返回。
这时可以通过在onSubmit提交函数中控制这个属性:
const onSubmit = (values, onSubmitProps) => {
onsubmitProps.setSubmitting(false);
}
因此最终的提交按钮代码:
<button type='submit' disabled={!formik.isValid || formik.isSubmitting}>