Formik简介
增强表单处理能⼒. 简化表单处理流程. 官⽹
Formik 下载
npm install formik
基本使用
使⽤ formik 进⾏表单数据绑定以及表单提交处理
-
useFormik 方法接收一个对象,返回值也是一个对象
-
- initialValues为初始化数据值
- onSubmit 为表单提交方法, 形参 values 表单提交行为获取的数据
-
表单通过name进行绑定
-
handleSubmit 表单提交方法,自动绑定onSubmit
-
formik.handleChange 方法,用于同步对应表单值
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
表单验证
初始验证方式
- validate 用于表单校验,返回一个自定义对象 errors, 在内部写验证函数
- formik.errors 可以获取验证结果
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>15){
errors.username='用户名的长度不能大于15'
}
if(values.password<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?formik.errors.username:null}</p>
<input
type="password"
name="password"
value={formik.values.password}
onChange={formik.handleChange}
/>
{/* 没有验证通过的提示信息 */}
<p>{formik.errors.password?formik.errors.password:null}</p>
<input type="submit" />
</form>
)
}
export default App
初始验证方式优化
- 以上代码虽能完成验证功能,但用户体验并不好,当将默认值置空时,initialValues: { username: ‘’, password: ‘’ },在表单输入用户名,会发现密码的验证提示显示。 所以需要进一步优化以提高用户体验。
- 开启离开焦点事件触发验证 onBlur={formik.handleBlur}
- 判断当前的表单数据是否被更改formik.touched
- 两者结合使用,缺一不可
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>15){
errors.username='用户名的长度不能大于15'
}
if(values.password<6) {
errors.password='密码的长度不能小于6'
}
return errors
},
onSubmit:(values)=>{
console.log(values) // 获取最新数据
}
})
return (
<form onSubmit={formik.handleSubmit}>
{/* onBlur={formik.handleBlur} 离开焦点 */}
<input
type="text"
name="username"
value={formik.values.username}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{/* 没有验证通过的提示信息 */}
{/* 离开焦点之后要formik.touched 离开焦点和formik.touched缺一不可*/}
{/* 先看数据有没有被更改 如果被更改在看看有没有验证通过 如果没有验证通过显示 formik.errors.username 否则什么都不显示*/}
<p>{formik.touched.username&&formik.errors.username?formik.errors.username:null}</p>
<input
type="password"
name="password"
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{/* 没有验证通过的提示信息 */}
{/* 先看数据有没有被更改 如果被更改在看看有没有验证通过 如果没有验证通过显示 formik.errors.username 否则什么都不显示*/}
<p>{formik.touched.username&&formik.errors.password?formik.errors.password:null}</p>
<input type="submit" />
</form>
)
}
export default App
使用yup结合useFormik使用
import React from "react";
import { useFormik } from 'formik'
import * as Yup from 'yup'
function App() {
const formik = useFormik({
initialValues:{username:"",password:""},
// validate:values=>{
// const errors={}
// if(!values.username){
// errors.username='请输入用户名'
// }else if(values.username>15){
// errors.username='用户名的长度不能大于15'
// }
// if(values.password<6) {
// errors.password='密码的长度不能小于6'
// }
// return errors
// },
// 基于Yup 很显然代码少很多
validationSchema:Yup.object({
username: Yup.string() // 定义username类型必须是字符串
.max(15, '用户名的长度不能大于15')
.required('请输入用户名'),
password: Yup.string()// 定义password类型必须是字符串
.max(20, '密码的长度不能大于20')
.required('请输入密码')
}),
onSubmit:(values)=>{
console.log(values) // 获取最新数据
}
})
return (
<form onSubmit={formik.handleSubmit}>
{/* onBlur={formik.handleBlur} 离开焦点 */}
<input
type="text"
name="username"
value={formik.values.username}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{/* 没有验证通过的提示信息 */}
{/* 离开焦点之后要formik.touched 离开焦点和formik.touched缺一不可*/}
{/* 先看数据有没有被更改 如果被更改在看看有没有验证通过 如果没有验证通过显示 formik.errors.username 否则什么都不显示*/}
<p>{formik.touched.username&&formik.errors.username?formik.errors.username:null}</p>
<input
type="password"
name="password"
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{/* 没有验证通过的提示信息 */}
{/* 先看数据有没有被更改 如果被更改在看看有没有验证通过 如果没有验证通过显示 formik.errors.username 否则什么都不显示*/}
<p>{formik.touched.username&&formik.errors.password?formik.errors.password:null}</p>
<input type="submit" />
</form>
)
}
export default App
减少样板代码
import React from "react";
import { useFormik } from 'formik'
import * as Yup from 'yup'
function App() {
const formik = useFormik({
initialValues: { username: "", password: "" },
// 基于Yup 很显然代码少很多
validationSchema: Yup.object({
username: Yup.string() // 定义username类型必须是字符串
.max(15, '用户名的长度不能大于15')
.required('请输入用户名'),
password: Yup.string()// 定义password类型必须是字符串
.max(20, '密码的长度不能大于20')
.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}
{...formik.getFieldProps('username')}
/>
<p>{formik.touched.username && formik.errors.username ? formik.errors.username : null}</p>
<input
type="password"
name="password"
// value={formik.values.password}
// onChange={formik.handleChange}
// onBlur={formik.handleBlur}
{...formik.getFieldProps('password')}
/>
<p>{formik.touched.password && formik.errors.password ? formik.errors.password : null}</p>
<input type="submit" />
</form>
)
}
export default App
使用组件的方式构建表单
组件内封装好的组件
-
Formik 表单最外层,可传递数据
-
- initialValue 表单默认数据
- onSubmit 表单提交行为
- validationSchema 表单验证规则
-
Form 表单组件
-
Field 具体表单项
-
ErrorMessage 表单项提示信息显示
import React from "react";
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
function App() {
const initialValues = {
username: '' // 默认信息
}
const handleSubmit = (values) => {
console.log(values)
}
const Schema = Yup.object({
username: Yup.string()
.max(12, '用户名长度不能大于12')
.required('请输入用户名')
})
return <Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={Schema}
>
<Form>
<Field name="username"></Field>
<ErrorMessage name="username"></ErrorMessage>
<input type='submit' />
</Form>
</Formik>
}
export default App
构建其他表单项
- 默认情况下,Filed组件渲染的是文本框, 若要生成其他表单元素可以使用如下语法
- as 指定类型
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 handleSubmit = (values) => {
console.log(values)
}
const Schema = Yup.object({
username: Yup.string()
.max(12, '用户名长度不能大于12')
.required('请输入用户名')
})
return <Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={Schema}
>
<Form>
<Field name="username"></Field>
<Field name="content" as="textarea"></Field>
<Field name="subject" as="select">
<option value='前端'>前端</option>
<option value='java'>java</option>
</Field>
<ErrorMessage name="username"></ErrorMessage>
<input type='submit' />
</Form>
</Formik>
}
export default App
构建自定义表单控件
- formik提供的表单控件不能构建密码框、复选框这些,需要自定义
- 使用 useFiled 去构建自定义表单控件
import React from "react";
import { Formik, Form, Field, useField } from 'formik';
import * as Yup from 'yup';
function MyInput({ label, ...props }) {
// filed 表单属性 meta存放验证信息
const [field, meta] = useField(props)
// console.log(field,'field')
// console.log(meta,'meta')
// 构建视图
return <div>
<label htmlFor={props.id} >{label}</label>
<input {...field} {...props} />
{/* 判断值有没有被修改过(meta.touched)并且验证meta.error是否为真 如果是就是知道验证没有通过*/}
{meta.touched && meta.error ? <span>{meta.error}</span> : null}
</div>
}
function App() {
const initialValues = {
username: '', // 默认信息
}
const handleSubmit = (values) => {
console.log(values)
}
const Schema = Yup.object({
username: Yup.string()
.max(12, '用户名长度不能大于12')
.required('请输入用户名'),
password: Yup.string()
.min(6, '密码验证没有通过')
.required('请输入密码'),
})
return <Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={Schema}
>
<Form>
<Field name="username"></Field>
<MyInput id="myPass" label="密码" name="password" type="password" placeholder="请输入密码" />
<input type='submit' />
</Form>
</Formik>
}
export default App
自定义复选框控件
需要先验证通过输入框
import React from "react";
import { Formik, Form, Field, useField } from 'formik';
import * as Yup from 'yup';
function Checkbox({ label, ...props }) {
// helper 对象中 存方法
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={props.id} >
<input
// 默认选中
checked={value.includes(props.value)}
type="checkbox"
{...props}
onChange={handleChange} />
{label}
</label>
</div>
}
function App() {
const initialValues = {
username: '', // 默认信息
hobbies:[] // 初始值
}
const handleSubmit = (values) => {
console.log(values)
}
const Schema = Yup.object({
username: Yup.string()
.max(12, '用户名长度不能大于12')
.required('请输入用户名'),
})
return <Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={Schema}
>
<Form>
<Field name="username"></Field>
<Checkbox value="足球" label="足球" name="hobbies" />
<Checkbox value="篮球" label="篮球" name="hobbies" />
<Checkbox value="橄榄球" label="橄榄球" name="hobbies" />
<input type='submit' />
</Form>
</Formik>
}
export default App
受控组件和非受控组件区别
非受控组件
表单数据由DOM节点管理,特点是表单数据在需要时进行获取,代码实现相对简单
受控组件
表单数据由state对象管理,特点是可以实时得到表单数据,代码相对复杂
选⽤标准
总结: 受控组件和⾮受控组件都有其特点, 应该根据需求场进⾏选择. 在⼤多数情况下, 推荐使⽤受控组件处理表单数据. 如果表单在数据交互⽅⾯⽐简单, 使⽤⾮受控表单, 否则使⽤受控表单.
tisp:不过建议还是选择受控组件