react-hook-form 使用小结

表单状态管理曾经一直是让前端头疼的问题,错误提示,校验规则,动态表单,重置。。。搞得人头大。好在近几年也出现了不少好的社区方案,比如 Formik, react-hook-form, react-final-form等等,今天我们来谈谈其中的 react-hook-form。

useForm

useForm 是最基础的表单状态管理钩子,它接受以下参数:

const {
  handleSubmit,
  watch
} = useForm({
  defaultValues: {},
  mode: 'onSubmit' // onChange | onBlur | onSubmit | onTouched | all
})

mode 可以控制触发校验的时机,如果我们希望用户能尽快感知到填写出错了,可以使用 'all';

defaultValues, 如果表单从后台拉下来数据,有初始值,可以从这里传进去。

rules

rules可以用来校验值,支持以下字段:

{
required: true,
maxLength; // 最大长度
minLength; //最小长度
max: 5 // 最大值
min: 5 // 最小值
pattern: /1\d{12}/
validate: (v) => v > 100
validate: {
        greaterThan: (v) => v > 100,
        lessThan: (v) => v< 200
        }
}

使用<Controller />来和UI库集成

使用useForm返回的register函数,可以很方便地使用原生html元素构建一个表单,但是大部分情况下,我们是使用UI库来开发表单的。

<Controller/>组件接受control, name,rules和 render函数等作为属性,render函数接受field, fieldState, formState3个参数:field里面包括用来控制字段的onChange函数和value,fieldState 包含字段的校验信息。通过这些信息,我们就可以控制这个字段是应该怎么渲染;

    field: { onChange, onBlur, value, name, ref },
    fieldState: { invalid, isTouched, isDirty, error },
    formState,
<Controller
  control={control}
  rules={{ required: true }}
  name="test"
  render={({
    field: { onChange, onBlur, value, name, ref },
    fieldState: { invalid, isTouched, isDirty, error },
    formState,
  }) => (
    <Checkbox
      onBlur={onBlur} // notify when input is touched
      onChange={onChange} // send value to hook form
      checked={value}
      inputRef={ref}
    />
  )}
/>

watch和useWatch 构建动态表单

经常有这样的场景,就是一个输入,会影响接下来的表单展示。由于useForm的表单状态发生变化,并不一定会触发重新渲染,当我们需要当值发生变化的时候更新UI,我们需要用到useWatch或者watch;

假设有这么一个场景,我们需要实时回显用户的输入,那么可以这么写:

const watchedName = watch('name', '');

return <div>
    <label>Name</label>
    <input
        type="text"
            {...register("name", { required: true, maxLength: 50 })}
    />
    <div>name: {watchedName}</div>
</div>

这时,当输入框的字段更新时,就会触发重新渲染,从而回显用户输入的值。那么watchuseWatch的区别是啥呢,watch是 useForm钩子的返回值,useWatch是一个全新的钩子函数,在一些不需要父组件更新的场景下,可以获得更好的性能。下面这个例子将watch传入子组件,可以发现,子组件更新时父组件也更新了。

useFieldArray来新增表单项

我们经常会遇到这样的场景--新增表单项,比如新增收货地址。use-hook-form为我们提供了useFieldArray这个hook来完成这些工作:

  const { register, control, handleSubmit, reset, watch } = useForm({
    defaultValues: {
      test: [{ firstName: "Bill", lastName: "Luo" }]
    }
  });
  const {
    fields,
    append,
    prepend,
    remove,
    swap,
    move,
    insert,
    replace
  } = useFieldArray({
    control,
    name: "test"
  });

我们可以使用prepend在队首插入一个表单项,append在队尾插入一个表单项,remove来去掉一个表单项。当然如果我们希望实时显示表单项里的数据的时候,还是要使用watchuseWatch