Skip to main content

react-hook-form的设计思想

一个表单,form标签下具备许多的子元素,每个子元素都具备输入的功能,在用户输入的过程中以及最终提交的过程中都可能会涉及到校验,这个校验的过程中会可能会发生校验失败等错误信息。对于这个表单的分析,需要提炼一下几个需要思考的关键点:

  • 字段以及对应的值如何管理
  • 提交时候的校验与失焦校验如何实现
  • 提交的时候校验到错误聚焦比较容易,但是滚动到对应的错误输入DOM会很艰难
  • 为什么存在大量的手动重新渲染

🍀字段以及对应的值如何管理

字段以及对应的值都会被存储在Ref中,由于Ref的变化不会导致组件的渲染,因此需要一个手动渲染的工具:const [, render] = useState();,这里每次都可以通过render({})来手动渲染组件。

0️⃣fieldsRef数据结构:

{
一些有关校验规则的选项
ref: {name,...} // 一个DOM元素对应的ref引用
}[]

1️⃣注册:将字段保存到ref中

这里通过register来注册每个字段,每个字段field在注册的时候,通过register,直接将字段名字存储在fieldsRef[field].ref.name上,比如:

<input name="exampleRequired" ref={register({ required: true })} />

这里fieldsRef['exampleRequired'].ref是一个input这个DOM对应的ref,这个ref上name属性值为exampleRequired。

register({ name: "antDInput" });

手动注册,这里的{ name: "antDInput" }存储在fieldsRef['antDInput'].ref上。

2️⃣手动设置值setValue时候触发校验: 调用combineFieldValues

setValue: (name: string, value: any, shouldValidate?: boolean) => void

3️⃣手动获取值getValues时候触发校验: 调用combineFieldValues

getValues: (payload?: { nest: boolean }) => Object

4️⃣每个DOM上绑定的事件触发的时候触发校验: 调用combineFieldValues

5️⃣提交校验: 调用combineFieldValues

提交的时候进行校验,并将拼接成的form数据传入自当以的submit函数:

handleSubmit: (data: Object, e: Event) => void

🍀提交时候的校验与失焦校验如何实现

对于自动注册register:由于DOM对应的ref会被保存下来,因此失焦或者实时校验会通过为DOM添加事件监听函数来实现,并每次DOM的value的值变化的时候,对应的ref中的值也是动态变化的。而提交的时候,可以从保存的各个ref中将数据搜集起来用于校验与提交。

<input name="exampleRequired" ref={register({ required: true })} />

对于手动注册register:由于DOM对应的ref无法保存,因此需要调用手动设置值的方式setValue来更新DOM上变化的值,以及实时校验这个变化的值。

register({ name: 'test' }, { required: true, min: 2 })

<button type="button" onClick={() => {
// manually set the 'test' field with value 'bill'
setValue('test', 'bill')
}}>SetValue</button>

🍀提交的时候校验到错误聚焦比较容易,但是滚动到对应的错误输入DOM会很艰难

在手动注册的时候,由于无法将DOM元素的ref保存下来,因此无法在提交的时候自动聚焦到校验失败的第一个DOM元素,但是自动注册由于保存了DOM的ref,因此可以自动聚焦。但是自动聚焦并且滚动到对应的位置还需要写对应的逻辑。

🍀为什么存在大量的手动重新渲染

在设置值setValue的时候,因为这些value存储在ref中,因此每次改变都不会重渲染,因此每次setValue都需要手动渲染