Formik 受控表单库
最近使用antd Form 有点痛苦,看到 React 官网推荐了 Formik 表单库,所赶紧去搂了一遍官网,下面是一个大概的介绍,具体使用之后再慢慢更新😝
handleChange/setFieldValue —— 通过 setFieldValue 或 handleChange 模拟事件,可以同时修改多个 input 的值
values —— 通过拦截、篡改 values ,直接影响表单显示的值
errors —— 通过拦截、篡改 errors ,方便自定义表单验证消息
这个表单库在运作中始终保持 single source of truth(单一数据源) —— view 的数据始终来自 values 和 errors,表单值的变化始终由 handleChange 发起
其实 useFormik() 还返回了 setFieldError 函数,可以用来设置 errors。 这个设计类似于 setFieldValue。
但是 setFieldError 和 setFieldValue 都会触发重新渲染,所以使用不当会造成无限循环渲染。
Formik 每一次修改都会触发整个表单的全局渲染。 但是其实 formik 最推崇的 FastField + ErrorMessage 的形式是可以有效避免这个问题的,这两个组件都在 shouldComponentUpdate 做了简单的浅层比较来避免不必要的重新渲染。
在输出错误信息的时候,通常有 touched.name && errors.name && errors.name 的判断,这个判断不依赖与 onBlur 事件的绑定这是因为 formik 在做表单校验的时候,会将全字段都检查一遍,不管用户有没有操作,但是对于用户来说,通常不希望在还没有操作的字段显示一行错误信息,所以需要 touched 字段查看该字段是否已经操作过,操作过并且有错误,才显示。
通过 Formik 组件传入初始字段,校验规则,提交事件;并在表单中绑定上 handleSubmit,handleChange,handleBlur 等事件后,我们就能够实现一个简单表单操作。
如果您熟悉使用普通 React 构建表单,您可以认为 Formik 的 handleChange 工作方式如下:
const [values, setValues] = React.useState({});
const handleChange = event => {
setValues(prevValues => ({
...prevValues,
// we use the name to tell Formik which key of `values` to update
[event.target.name]: event.target.value
});
}
formik.errors 通过自定义验证函数填充。默认情况下,Formik 将在每次击键(更改事件)、每个输入的模糊事件以及提交之前进行验证。onSubmit 我们传递给的函数 useFormik()只有在没有错误时才会执行(即如果我们的 validate 函数返回{})
getFieldProps()
上面的代码非常明确地说明了 Formik 正在做什么。onChange-> handleChange、onBlur->handleBlur 等。但是,为了节省您的时间,useFormik()返回一个调用的辅助方法 formik.getFieldProps(),以加快连接输入的速度。给定一些字段级别的信息,它会为您返回给定字段的 onChange, onBlur, value。然后,您可以传播上的 input,select 或 textarea。
代码由
<input
id="email"
name="email"
type="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
/>
转换为
<input id="email" type="email" {...formik.getFieldProps('email')} />
使用 useField 来包装我们自己的组件
const MyTextInput = ({ label, ...props }) => {
// useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
// which we can spread on <input>. We can use field meta to show an error
// message if the field is invalid and it has been touched (i.e. visited)
const [field, meta] = useField(props);
return (
<>
<label htmlFor={props.id || props.name}>{label}</label>
<input className="text-input" {...field} {...props} />
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
}
默认情况下,Formik 将按如下方式运行验证方法:
- 在“更改”事件/方法(更新的东西 values)之后
handleChange
setFieldValue
setValues
- 在“模糊”事件/方法(更新的东西 touched)之后
handleBlur
setTouched
setFieldTouched
- 每当尝试提交时
handleSubmit
submitForm
- 还有通过 Formik 的渲染/注入道具提供给您的命令式辅助方法,您可以使用它们来命令式调用验证。
validateForm
validateField
我可以将
null
作为错误消息返回吗?
不,请 undefined 改用。Formik 用于 undefined 表示空状态。如果您使用 null,Formik 的计算道具的几个部分(isValid 例如)将无法按预期工作。
使用 isSubmittimg 来防止表单重复提交
formik 动态添加或删除某一项
感觉和 antd 还是有点像