formik来实现表单校验
表单验证说明
- 表单提交前,需要先进性表单验证,验证通过后再提交表单
- 方式一:antd-mobile 组件库的方式(需要InputItem文本输入组件)
- 推荐:使用更通用的 formik,React中专门用来进行表单处理和表单校验的库
介绍
- Github地址:formik文档
- 场景:表单处理,表单验证
- 优势:轻松处理React中的复杂表单,包括:获取表单元素的值,表单验证和错误信息,处理表单提交,并且将这些内容放在一起统一处理,有利于代码阅读,重构,测试等
- 使用两种方式:1. 高阶组件(withFormik) 2. render-props(<Formik render={() => {}} />)
formik来实现表单校验(★★★)
重构
- 安装: yarn add formik
- 导入 withFormik,使用withFormit 高阶组件包裹Login组件
- 为withFormit提供配置对象: mapPropsToValues / handleSubmit
- 在Login组件中,通过props获取到values(表单元素值对象),handleSubmit,handleChange
- 使用values提供的值,设置为表单元素的value,使用handleChange设置为表单元素的onChange
- 使用handleSubmit设置为表单的onSubmit
- 在handleSubmit中,通过values获取到表单元素值
- 在handleSubmit中,完成登录逻辑
// Login组件中
render() {
// const { username, password } = this.state
// 通过 props 获取高阶组件传递进来的属性
const { values, handleSubmit, handleChange } = this.props
return (
<div className={styles.root}>
{/* 顶部导航 */}
<NavHeader className={styles.navHeader}>账号登录</NavHeader>
<WhiteSpace size="xl" />
{/* 登录表单 */}
<WingBlank>
<form onSubmit={handleSubmit}>
<div className={styles.formItem}>
<input
className={styles.input}
value={values.username}
onChange={handleChange}
name="username"
placeholder="请输入账号"
/>
</div>
{/* 长度为5到8位,只能出现数字、字母、下划线 */}
{/* <div className={styles.error}>账号为必填项</div> */}
<div className={styles.formItem}>
<input
className={styles.input}
value={values.password}
onChange={handleChange}
name="password"
type="password"
placeholder="请输入密码"
/>
</div>
{/* 长度为5到12位,只能出现数字、字母、下划线 */}
{/* <div className={styles.error}>账号为必填项</div> */}
<div className={styles.formSubmit}>
<button className={styles.submit} type="submit">
登 录
</button>
</div>
</form>
<Flex className={styles.backHome}>
<Flex.Item>
<Link to="/registe">还没有账号,去注册~</Link>
</Flex.Item>
</Flex>
</WingBlank>
</div>
)
}
// 使用 withFormik 高阶组件包装 Login 组件,为 Login 组件提供属性和方法
Login = withFormik({
// 提供状态:
mapPropsToValues: () => ({ username: '', password: '' }),
// 表单的提交事件
handleSubmit: async (values, { props }) => {
// 获取账号和密码
const { username, password } = values
// 发送请求
const res = await API.post('/user/login', {
username,
password
})
console.log('登录结果:', res)
const { status, body, description } = res.data
if (status === 200) {
// 登录成功
localStorage.setItem('hkzf_token', body.token)
// 注意:无法在该方法中,通过 this 来获取到路由信息
// 所以,需要通过 第二个对象参数中获取到 props 来使用 props
props.history.go(-1)
} else {
// 登录失败
Toast.info(description, 2, null, false)
}
}
})(Login)
两种表单验证方式
-
两种方式
- 通过validate 配置手动校验
- 通过 validationSchema 配置项配合Yup来校验
- 推荐: validationSchema配合Yup的方式进行表单校验
给登录功能添加表单验证
- 安装: yarn add yup (Yup 文档),导入Yup
// 导入Yup
import * as Yup from 'yup'
- 在 withFormik 中添加配置项 validationSchema,使用 Yup 添加表单校验规则
- 在 Login 组件中,通过 props 获取到 errors(错误信息)和 touched(是否访问过,注意:需要给表单元素添加 handleBlur 处理失焦点事件才生效!)
- 在表单元素中通过这两个对象展示表单校验错误信
示例代码:
// 使用 withFormik 高阶组件包装 Login 组件,为 Login 组件提供属性和方法
Login = withFormik({
...
// 添加表单校验规则
validationSchema: Yup.object().shape({
username: Yup.string()
.required('账号为必填项')
.matches(REG_UNAME, '长度为5到8位,只能出现数字、字母、下划线'),
password: Yup.string()
.required('密码为必填项')
.matches(REG_PWD, '长度为5到12位,只能出现数字、字母、下划线')
}),
...
})(Login)
在结构中需要渲染错误信息:
{/* 登录表单 */}
<WingBlank>
<form onSubmit={handleSubmit}>
... 用户名的错误提示
{errors.username && touched.username && (
<div className={styles.error}>{errors.username}</div>
)}
... 密码框的错误提示
{errors.password && touched.password && (
<div className={styles.error}>{errors.password}</div>
)}
...
</WingBlank>
简单处理
- 导入 Form组件,替换form元素,去掉onSubmit
- 导入Field组件,替换input表单元素,去掉onChange,onBlur,value
- 导入 ErrorMessage 组件,替换原来的错误消息逻辑代码
- 去掉所有 props
示例代码:
// 导入withFormik
import { withFormik, Form, Field, ErrorMessage } from 'formik'
<Form>
{/* 账号 */}
<div className={styles.formItem}>
<Field
className={styles.input}
name="username"
placeholder="请输入账号"
/>
</div>
<ErrorMessage
className={styles.error}
name="username"
component="div"
/>
{/* 密码 */}
<div className={styles.formItem}>
<Field
className={styles.input}
name="password"
type="password"
placeholder="请输入密码"
/>
</div>
<ErrorMessage
className={styles.error}
name="password"
component="div"
/>
<div className={styles.formSubmit}>
<button className={styles.submit} type="submit">
登 录
</button>
</div>
</Form>