如何在组件外校验React Hook Form分步表单是否提交成功
核心问题
- 原生
submit事件仅能监听到表单提交动作,无法获取React Hook Form内部的校验结果、提交成功状态,即使表单校验失败触发了原生提交事件,依然会直接执行跳步逻辑 - 动态绑定的DOM事件未做清理,步骤切换时会重复绑定事件,导致逻辑执行异常
- 用原生
form属性关联跨组件表单的方式,和React Hook Form的受控提交逻辑不兼容
可用解决方案
方案1:状态提升关联提交回调
如果分步表单和步骤控制器属于同一父组件,通过props传递提交成功回调触发跳步:
// 子表单组件示例 import { useForm } from 'react-hook-form' export default function StepForm({ onSubmitSuccess }) { const { register, handleSubmit, formState: { errors } } = useForm() const onSubmit = async (data) => { // 执行当前表单的提交逻辑,比如调用接口保存数据 onSubmitSuccess() // 提交成功后通知父组件跳转 } return <form onSubmit={handleSubmit(onSubmit)} id="current-step-form"> {/* 表单字段内容 */} </form> }
父组件直接通过回调控制步骤:
// 父组件逻辑 const [step, setStep] = useState(0) const steps = [ { component: Step1Form }, { component: Step2Form }, { component: Step3Form } ] const CurrentForm = steps[step].component return <div> <CurrentForm onSubmitSuccess={() => step !== 2 && setStep(step + 1)} /> </div>
方案2:父组件控制下一步按钮时,用ref调用子表单提交方法
如果下一步按钮放在父组件,通过useImperativeHandle暴露子表单的提交校验方法给父组件调用:
// 子表单组件 import { useForm, useImperativeHandle, forwardRef } from 'react-hook-form' const StepForm = forwardRef((props, ref) => { const { register, trigger, getValues } = useForm() // 暴露方法给父组件 useImperativeHandle(ref, () => ({ validateAndSubmit: async () => { const isValid = await trigger() // 触发全表校验 if (!isValid) return false const formData = getValues() // 执行提交逻辑,调用接口等 return true } })) return <form>{/* 表单字段 */}</form> })
父组件点击下一步时调用子表单方法:
// 父组件逻辑 const formRef = useRef(null) const [step, setStep] = useState(0) const handleNext = async () => { const submitSuccess = await formRef.current?.validateAndSubmit() if (submitSuccess && step !== 2) { setStep(step + 1) } } return <div> <StepForm ref={formRef} /> <button type='button' onClick={handleNext} className="hvr-i-right"> {step !== 2 ? '下一步' : '完成'} <i className="material-icons hvr-i">arrow_forward</i> </button> </div>
原有逻辑修复方案
如果需要保留现有原生form关联的写法,需自定义提交成功事件触发跳步,同时添加事件清理逻辑:
// 父组件监听自定义提交成功事件 useEffect(() => { if (!steps || step === undefined) return const formEl = document.getElementById(steps[step].form) const handleSubmitSuccess = () => { if (step !== 2) setStep(prev => prev + 1) } formEl?.addEventListener('formSubmitSuccess', handleSubmitSuccess) // 组件卸载/步骤切换时清理事件 return () => { formEl?.removeEventListener('formSubmitSuccess', handleSubmitSuccess) } }, [step, steps])
子表单提交成功后触发自定义事件:
// 子表单提交逻辑中添加 const onSubmit = async (data) => { // 提交成功后 const successEvent = new CustomEvent('formSubmitSuccess') document.getElementById('当前表单id')?.dispatchEvent(successEvent) }
内容的提问来源于stack exchange,提问作者SantiagoP
相关产品推荐
相关产品推荐

