Formik

React 表单增强。增强表单处理能力,简化表单处理流程。

官网(https://jaredpalmer.com/formik/)

npm install formik -S

基础使用

使用 formik 进行表单数据绑定以及表单提交处理。

import React from 'react'; import { useFormik } from 'formik'; function App () { const formik = useFormik({ initialValues: { username: '张三', password: '123456' }, onSubmit: values => { console.log(values); } }) return ( <form onSubmit={ formik.handleSubmit }> <input type="text" name="username" value={ formik.values.username } onChange={ formik.handleChange } /> <input type="password" name="password" value={ formik.values.password } onChange={ formik.handleChange } /> <input type="submit" /> </form> ); } export default App;

表单验证

数据验证

import React from 'react'; import { useFormik } from 'formik'; function App () { const formik = useFormik({ initialValues: { username: '张三', password: '123456' }, validate: values => { const errors = {}; if (!values.username) { errors.username = '请输入用户名' } else if (!values.username.length > 15) { errors.username = '用户名长度不能大于 15' } if (values.password.length < 6) { errors.password = '密码长度必须大于 6 位' } return errors; }, onSubmit: values => { console.log(values); } }) return ( <form onSubmit={ formik.handleSubmit }> <input type="text" name="username" value={ formik.values.username } onChange={ formik.handleChange } /> <p>{ formik.errors.username }</p> <input type="password" name="password" value={ formik.values.password } onChange={ formik.handleChange } /> <p>{ formik.errors.password }</p> <input type="submit" /> </form> ); } export default App;

体验效果优化

提示信息时检查表单元素的值是否被更改。

import React from 'react'; import { useFormik } from 'formik'; function App () { const formik = useFormik({ initialValues: { username: '', password: '' }, validate: values => { const errors = {}; if (!values.username) { errors.username = '请输入用户名' } else if (!values.username.length > 15) { errors.username = '用户名长度不能大于 15' } if (values.password.length < 6) { errors.password = '密码长度必须大于 6 位' } return errors; }, onSubmit: values => { console.log(values); } }) return ( <form onSubmit={ formik.handleSubmit }> <input type="text" name="username" value={ formik.values.username } onChange={ formik.handleChange } onBlur={ formik.handleBlur } /> <p>{ formik.touched.username && formik.errors.username ? formik.errors.username : '' }</p> <input type="password" name="password" value={ formik.values.password } onChange={ formik.handleChange } onBlur={ formik.handleBlur } /> <p>{ formik.touched.password && formik.errors.password ? formik.errors.password : '' }</p> <input type="submit" /> </form> ); } export default App;

简化表单验证

formik 配合 yup 进行表单验证。

npm install yup -S
import React from 'react'; import { useFormik } from 'formik'; import * as Yup from 'yup'; function App () { const formik = useFormik({ initialValues: { username: '', password: '' }, validationSchema: Yup.object({ username: Yup.string().max(15, '用户名长度不能大于 15').required('请填写用户名'), password: Yup.string().min(6, '密码长度必须大于 6 位').required('请填写密码') }), onSubmit: values => { console.log(values); } }); return ( <form onSubmit={ formik.handleSubmit }> <input type="text" name="username" value={ formik.values.username } onChange={ formik.handleChange } onBlur={ formik.handleBlur } /> <p>{ formik.touched.username && formik.errors.username ? formik.errors.username : '' }</p> <input type="password" name="password" value={ formik.values.password } onChange={ formik.handleChange } onBlur={ formik.handleBlur } /> <p>{ formik.touched.password && formik.errors.password ? formik.errors.password : '' }</p> <input type="submit" /> </form> ); } export default App;

简化表单代码

减少样板代码

{ ...form.getFieldProps('username') }

简化后代码如下:

import React from 'react'; import { useFormik } from 'formik'; import * as Yup from 'yup'; function App () { const formik = useFormik({ initialValues: { username: '', password: '' }, validationSchema: Yup.object({ username: Yup.string().max(15, '用户名长度不能大于 15').required('请填写用户名'), password: Yup.string().min(6, '密码长度必须大于 6 位').required('请填写密码') }), onSubmit: values => { console.log(values); } }); return ( <form onSubmit={ formik.handleSubmit }> <input type="text" name="username" { ...formik.getFieldProps('username') } /> <p>{ formik.touched.username && formik.errors.username ? formik.errors.username : '' }</p> <input type="password" name="password" { ...formik.getFieldProps('password') } /> <p>{ formik.touched.password && formik.errors.password ? formik.errors.password : '' }</p> <input type="submit" /> </form> ); } export default App;

组件方式构建表单

import React from 'react'; import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; function App () { const initialValues = { username: '' }; const schema = Yup.object({ username: Yup.string().max(15, '用户名长度不能大于 15').required('请输入用户名') }) const handleSubmit = (values) => { console.log(values); } return ( <Formik initialValues={ initialValues } onSubmit={ handleSubmit } validationSchema={ schema } > <Form> <Field name="username" /> <ErrorMessage name="username" /> <input type="submit" /> </Form> </Formik> ); } export default App;

field 组件 as 属性

默认情况下,Field 组件渲染的时文本框,如要生成其他表单元素可以使用以下语法。

import React from 'react'; import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; function App () { const initialValues = { username: '', content: '', subject: "java" }; const schema = Yup.object({ username: Yup.string().max(15, '用户名长度不能大于 15').required('请输入用户名') }) const handleSubmit = (values) => { console.log(values); } return ( <Formik initialValues={ initialValues } onSubmit={ handleSubmit } validationSchema={ schema } > <Form> <Field name="username" /> <ErrorMessage name="username" /> <Field as="textarea" name="content" /> <Field as="select" name="subject"> <option value="前端">前端</option> <option value="java">java</option> </Field> <input type="submit" /> </Form> </Formik> ); } export default App;

构建自定义表单控件

密码输入框

import React from 'react'; import { Formik, Form, Field, ErrorMessage, useField } from 'formik'; import * as Yup from 'yup'; function MyInput ({ label, ...props }) { const [ field, meta ] = useField(props); return ( <div> <label htmlFor={ props.id }>{ label }</label> <input { ...field } { ...props } /> { meta.touched && meta.error ? <span>{ meta.error }</span> : null } </div> ) } function App () { const initialValues = { username: '', content: '', subject: "java" }; const schema = Yup.object({ username: Yup.string().max(15, '用户名长度不能大于 15').required('请输入用户名'), password: Yup.string().min(6, '密码长度必须大于 6 位').required('请填写密码') }) const handleSubmit = (values) => { console.log(values); } return ( <Formik initialValues={ initialValues } onSubmit={ handleSubmit } validationSchema={ schema } > <Form> <Field name="username" /> <ErrorMessage name="username" /> <MyInput id="my-password" name="password" type="password" placeholder="请输入密码" label="密码" /> <input type="submit" /> </Form> </Formik> ); } export default App;

复选框

import React from 'react'; import { Formik, Form, Field, ErrorMessage, useField } from 'formik'; import * as Yup from 'yup'; function MyInput ({ label, ...props }) { const [ field, meta ] = useField(props); return ( <div> <label htmlFor={ props.id }>{ label }</label> <input { ...field } { ...props } /> { meta.touched && meta.error ? <span>{ meta.error }</span> : null } </div> ) } function Checkbox ({ label, ...props }) { const [ field, meta, helper ] = useField(props); const { value } = meta; const { setValue } = helper; const handleChange = () => { const set = new Set(value); if (set.has(props.value)) { set.delete(props.value); } else { set.add(props.value); } setValue([ ...set ]); } return ( <div> <label htmlFor=""> <input checked={ value.includes(props.value) } type="checkbox" { ...props } onChange={ handleChange } />{ label } </label> </div> ) } function App () { const initialValues = { username: '', hobbies: ['排球'] }; const schema = Yup.object({ username: Yup.string().max(15, '用户名长度不能大于 15').required('请输入用户名'), password: Yup.string().min(6, '密码长度必须大于 6 位').required('请填写密码') }) const handleSubmit = (values) => { console.log(values); } return ( <Formik initialValues={ initialValues } onSubmit={ handleSubmit } validationSchema={ schema } > <Form> <Field name="username" /> <ErrorMessage name="username" /> <MyInput id="my-password" name="password" type="password" placeholder="请输入密码" label="密码" /> <Checkbox value="足球" label="足球" name="hobbies" /> <Checkbox value="篮球" label="篮球" name="hobbies" /> <Checkbox value="排球" label="排球" name="hobbies" /> <input type="submit" /> </Form> </Formik> ); } export default App;