如何让react-hook-form多步骤表单的yup.test仅触发一次校验?
Yup异步校验重复执行问题原因及解决方案
问题原因
该问题确实和trigger方法的使用,以及react-hook-form配合yup的默认校验逻辑有关,核心原因如下:
- 你在三个节点都主动/被动触发了包含email/phone字段的校验规则
- 第一步点击下一步:主动调用
trigger(['email', 'password', 'passwordConfirm']),触发email的校验 - 第二步点击下一步:主动调用
trigger(['firstname', 'lastname', 'middlename', 'typeClient', 'phone']),默认配置下YupResolver会执行全量schema校验,哪怕你只指定触发部分字段,yup也会跑完所有字段的校验逻辑,所以这一步除了当前步骤的字段,email的校验也会被重新执行 - 最后点击提交按钮:react-hook-form的
handleSubmit方法默认会在提交前触发全表单所有字段的校验,所以email和phone的校验会再跑一次
- 第一步点击下一步:主动调用
- 你定义的
yup.test异步校验没有配置缓存逻辑,每次触发校验都会重新调用AuthService.checkEmail/checkPhone接口,没有复用之前的校验结果
解决方案
1. 配置YupResolver仅校验指定字段
如果你使用的是@hookform/resolvers里的yupResolver,初始化时开启partial模式,即可让trigger仅校验你指定的字段,不会执行全量schema校验:
import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from 'yup'; const schema = yup.object({ // 你的校验规则 }); useForm({ resolver: yupResolver(schema, { partial: true }), // 开启partial模式 // 其他表单配置 })
配置后第二步调用trigger时,就不会再触发第一步已经校验过的email字段的校验。
2. 提交时跳过重复全量校验(可选)
如果你能保证前面步骤的校验结果都是有效的,可以不用handleSubmit的默认校验逻辑,直接拿到表单值提交即可:
const handleRegister = () => { const formValues = getValues(); // 直接提交formValues即可 }
3. 给异步校验增加缓存逻辑
针对同一个email/phone值避免重复发起请求,可以增加缓存存储校验结果:
// 定义缓存容器 const emailCheckCache = new Map(); const phoneCheckCache = new Map(); // 改造校验规则 email: email.test( 'isUnique', translate('signupFormScheme.email_is_busy'), async (value) => { if (!value) return true; if (emailCheckCache.has(value)) return emailCheckCache.get(value); const checkResult = await AuthService.checkEmail(value) === true; emailCheckCache.set(value, checkResult); return checkResult; }, ), // phone字段校验规则同理增加缓存逻辑
内容的提问来源于stack exchange,提问作者Александр Бычков
相关产品推荐
相关产品推荐

