React 表单处理
# formik 表单处理
进行表单验证的库。轻松处理 React 中的复杂表单,包括:获取表单元素的值、表单验证和错误信息、处理表单提交。 并且将这些内容放在一起统一处理,有利于代码阅读、重构、测试等。
使用方式 :高阶组件 withFormik
、render-props <Formik render={() => {}} />
# 示例
下面以登录表单为例
# 使用步骤
安装
yarn add formik
导入withFormik
,使用 withFormik
高阶组件包裹 Login
组件。
Login = withFormik({
mapPropsToValues: () => ({ username: '',password: '' }), // 提供表单项的值
handleSubmit: (values, { props }) => {}, // 提供表单提交事件
})(Login)
2
3
4
为 withFormik
提供配置对象:mapPropsToValues
与 handleSubmit
。 在 Login
组件中,通过 props
获取到 values
(表单元素值对象)、 handleSubmit
、handleChange
。
使用 values
提供的值,设置为表单元素的 value
,使用 handleChange
设置为表单元素的 onChange
。
注意
这里的handleChange
实现方式如下。(前提是受控表单组件添加量name属性)
handleChange = (name,value)=>{
this.setState({
[name]: value
})
}
2
3
4
5
# 代码
import React from 'react';
import styles from './index.module.scss'
import { withFormik } from 'formik'
class Login extends React.Component {
render() {
const {
values,
handleChange,
handleSubmit
} = this.props
return (
<div className={styles.app}>
<form className={styles.form} onSubmit={handleSubmit}>
<input
type="text"
name="username"
placeholder="请输入用户名"
value={values.username}
className={styles.input}
onChange={handleChange}
/>
<input
type="text"
name="password"
placeholder="请输入密码"
value={values.password}
className={styles.input}
onChange={handleChange}
/>
<input className={styles.btn} type="submit" value="提交" />
</form>
</div>
)
}
}
Login = withFormik({
mapPropsToValues: () => ({ username: '', password: '' }),
handleSubmit: (values, { props }) => {
/*
使用 handleSubmit 设置为表单的 onSubmit。
在 handleSubmit 中,通过 values 获取到表单元素值。
在 handleSubmit 中,完成登录逻辑。
*/
console.log("提交表单处理...", values, props) // props 是被包裹组件的 props
//发送登录请求
}
})(Login)
export default Login;
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
# 简化处理
formik 提供了 Form
, Field
组件,简化了在 withFormik
中包裹的子组件操作。
Form
组件免去了自己注册 onSubmit
等属性。
Field
组件代替了 HTML
的元素 type 属性代表是哪一种 HTML
元素。该组件免去了自己写 value
、onChange
等属性
由此简化了结构。
import React from 'react';
import styles from './index.module.scss'
import { withFormik, Form, Field } from 'formik'
class Login extends React.Component {
render() {
return (
<div className={styles.app}>
<Form className={styles.form} >
<Field
className={styles.input}
type="text"
name="username"
placeholder="请输入用户名"
/>
<Field
className={styles.input}
type="text"
name="password"
placeholder="请输入密码"
/>
<input className={styles.btn} type="submit" value="提交" />
</Form>
</div>
)
}
}
Login = withFormik({
mapPropsToValues: () => ({ username: '', password: '' }),
handleSubmit: (values, { props }) => {
console.log("提交表单处理...", values, props)
//发送登录请求
}
})(Login)
export default Login;
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
# 表单校验
使用
validationSchema
配合Yup
的方式进行表单校验。
# 步骤
安装 Yup
yarn add yup
在 withFormik
中添加配置项 validationSchema
,使用 Yup
添加表单校验规则。
在 Login
组件中,通过 props
获取到 errors
(错误信息)和 touched
(是否访问过,注意:需要给表单 元素添加 handleBlur
处理失焦点事件才生效!)。
# 示例
点击查看代码
// 验证规则:
const REG_UNAME = /^[a-zA-Z_\d]{5,8}$/
const REG_PWD = /^[a-zA-Z_\d]{5,12}$/
class Login extends Component {
render() {
return (
<div className={styles.root}>
<NavHeader className={styles.navHeader} title={'账号登录'} />
<WhiteSpace size="xl" />
<WingBlank>
<Form >
<div className={styles.formItem}>
<Field className={styles.input} name="username" placeholder="请输入账号" />
</div>
<ErrorMessage name='username' component='div' className={styles.error} />
<div className={styles.formItem}>
<Field className={styles.input} placeholder="请输入密码" name="password" />
</div>
<ErrorMessage name='password' component='div' className={styles.error} />
<div className={styles.formSubmit}>
<button className={styles.submit} type="submit">
登 录
</button>
</div>
</Form>
<Flex className={styles.backHome}>
<Flex.Item className={styles.center}>
<Link to="/registe">还没有账号,去注册~</Link>
</Flex.Item>
</Flex>
</WingBlank>
</div>
)
}
}
Login = withFormik({
mapPropsToValues: () => ({ username: '', password: '' }), // 对应于表单中的 name属性
handleSubmit: async (values, { props }) => {
const { username, password } = values
let res = await API.post('/user/login', {
username,
password
})
const { status, description, } = res.data
const { state } = props.location
if (status === 200) {
const { body: { token } } = res.data
setToken(token)
if (state) {
props.history.replace(state.from.pathname)
} else {
props.history.go(-1)
}
} else {
Toast.info(description, 2, null, false)
}
},
/*
添加 validationSchema 代表表单验证
Yup.object().shape({/....}) 代表要检验的是一个对象类型 shape 中的参数为约束规则
详细API 可以查阅官方文档
*/
validationSchema: Yup.object().shape({
username: Yup.string().required('账号为必填项!')
.matches(REG_UNAME, '长度为5到8位,只能出现数字、字母、下划线'),
password: Yup.string().required('账号为必填项!')
.matches(REG_PWD, '长度为5到12位,只能出现数字、字母、下划线'),
})
})(Login)
//使用高阶组件包装
export default Login
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
66
67
68
69
70
71
72
73
74
75
76
77
78