0%

使用 Formik +Yup 处理 React 表单验证

React 操作表单一直都是比较繁琐的操作,在以前用的是 redux-form, 但现在 formik 这个库设计得更加优雅,Github 的 star 数目已经远远超过 redux-form 了。做表单就是为了收集一些数据,然后进行提交。而 redux-form 理念是把这些数据存放到 reducer 中去,当我们表单多的时候,显然对整个 store 的数据管理不太友好,因为多了很多表单数据。而 formik 解决的其中一个痛点就是这个,它可以在组件内部处理这些表单项而简单易用。

Formik 旨在轻松管理具有复杂验证的表单, Formik 支持同步和异步表单级和字段级验证。

例子的 Formik 为 2.1.4 版

先来看个基本的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import React from 'react'
import { useFormik } from 'formik'
import './FormDemo.css'

// 检查表单字段
const validate = values => {
const errors = {}
if (!values.name) {
errors.name = '不能为空'
} else if (values.name.length > 20) {
errors.name = '名字太长,输入有误'
}

if (!values.email) {
errors.email = '不能为空'
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = '邮箱格式错误'
}

return errors
}

const FormDemo = () => {
const formik = useFormik({
initialValues: {
name: '',
email: '',
},
validate,
onSubmit: values => {
alert(JSON.stringify(values, null, 2))
},
})
return (
<form onSubmit={formik.handleSubmit} className='form-wrap'>
<div className='form-group'>
<label>名字</label>
<input
name='name'
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}
/>
{formik.touched.name && formik.errors.name ? (
<div className='error-tip'>{formik.errors.name}</div>
) : null}
</div>
<div className='form-group'>
<label>邮箱</label>
<input
name='email'
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
/>
{formik.touched.email && formik.errors.email ? (
<div className='error-tip'>{formik.errors.email}</div>
) : null}
</div>

<button type='submit'>Submit</button>
</form>
)
}
export default FormDemo

以上是一个很简单的表单,输入名字与邮箱。

上面例子中我们使用的是 useFormik 这种用法,还有使用 <Formik />withFormik 的用法。

但我们发现一个问题,当正在输入名字的时候,邮箱已经立马显示不能为空了,我们需要的是当点击的时候才做其他表单元素的判断而不是一次性判断完。对这一问题,我们需要再加一个判断touched, 这个代表表单中的某个字段是否被点击过,直译的话就是”触碰过”或”动过”,这样就不会出现上面的问题了

1
2
3
4
5
{
formik.touched.name && formik.errors.name ? (
<div className='error-tip'>{formik.errors.name}</div>
) : null
}

但发现上面的代码还是挺多, onChange, onBlur, value 等属性还是挺重复的,每个表单元素写一段,其实我们可以更精简,使用 formik 里面的getFieldProps方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<form onSubmit="{formik.handleSubmit}" className="form-wrap">
<div className="form-group">
<label>名字</label>
<input name='name' {...formik.getFieldProps('name')} /> {formik.touched.name &&
formik.errors.name ? (
<div className="error-tip">{formik.errors.name}</div>
) : null}
</div>
<div className="form-group">
<label>邮箱</label>
<input name='email' {...formik.getFieldProps('email')} /> {formik.touched.email &&
formik.errors.email ? (
<div className="error-tip">{formik.errors.email}</div>
) : null}
</div>

<button type="submit">Submit</button>
</form>

那么表单字段的验证能不能简化呢?formik 表单验证大多数我们会选择和 yup 库进行搭配,yup 的专长就是作规则校验的。用法如下:

1
2
3
4
5
6
7
8
9
const formik = useFormik({
// ...
validationSchema: Yup.object({
name: Yup.string().max(20, '名字太长,输入有误').required('不能为空'),
email: Yup.string().email('邮箱格式错误').required('不能为空'),
}),
// ...
})
// ...

上面 validationSchema 为 Formik 专门为 yup 留出的接口,所以 formik 是很好支持 yup 搭配使用的。

最后附上官网:https://jaredpalmer.com/formik/

-------------本文结束感谢您的阅读-------------