react-hook-form的onSubmit函数未触发,Controller管理Input异常求助
问题原因
- 你没有把
price状态的变更同步给React Hook Form(以下简称RHF)管理的表单字段,导致voucherPrice字段一直停留在初始的false值,不符合你定义的yup校验规则(正数字、必填),表单校验失败直接拦截了提交,所以onSubmit不会触发。 - 具体存在两处同步遗漏:
- 手动修改Input值时,你只调用了自定义的
handlePriceInputChange修改本地price状态,没有调用Controller注入的onChange方法通知RHF更新字段值 - 点击价格盒子修改
price时,完全没有同步更新RHF的对应字段值
- 手动修改Input值时,你只调用了自定义的
修复方案
修改后完全保留原有逻辑,Input始终展示price状态值,两个修改函数的运行效果和原来完全一致,仅补充RHF字段同步逻辑即可:
- 从
useForm的返回值中解构出setValue方法用于手动更新字段 - 在两处修改
price的位置补充字段同步逻辑 - 调整Controller的默认值匹配初始
price的空字符串状态
const schema = yup .object({ voucherPrice: yup.number().positive().required(), }) .required(); function PriceSelection(props) { const { register, handleSubmit, control, setValue, // 新增:解构setValue方法 formState: { errors }, } = useForm({ resolver: yupResolver(schema), }); const onSubmit = (data) => { console.log("does not work?", data); }; const classes = useStylesPriceSelection(); const [selected, setSelected] = useState(false); const [price, setPrice] = useState(""); const handleSelectedBox = (ev) => { console.log("", price); const newPrice = parseInt(ev.target.getAttribute("data-price")); setSelected(ev.target.getAttribute("data-boxprice")); setPrice(newPrice); setValue("voucherPrice", newPrice); // 新增:同步价格到RHF表单字段 }; const handlePriceInputChange = (ev) => { const inputValue = ev.target.value; const newPrice = inputValue ? parseInt(inputValue) : ""; // 处理空输入避免生成NaN console.log("change", newPrice); setPrice(newPrice); }; const priceBox1 = 25; const priceBox2 = 50; const priceBox3 = 75; const priceBox4 = 100; return ( <div> <section className={classes.priceBoxWrap}> <div data-boxprice="1" data-price={`${priceBox1}`} onClick={(ev) => handleSelectedBox(ev)} className={clsx( classes.priceBox, ((selected === "1" && price === priceBox1) || price === priceBox1) && classes.priceBoxSelected )} > {`${priceBox1}€`} </div> <div data-boxprice="2" data-price={`${priceBox2}`} onClick={(ev) => handleSelectedBox(ev)} className={clsx( classes.priceBox, ((selected === "2" && price === priceBox2) || price === priceBox2) && classes.priceBoxSelected )} > {`${priceBox2}€`} </div> </section> <section className={classes.priceBoxWrap}> <div data-boxprice="3" data-price={`${priceBox3}`} onClick={(ev) => handleSelectedBox(ev)} className={clsx( classes.priceBox, ((selected === "3" && price === priceBox3) || price === priceBox3) && classes.priceBoxSelected )} > {`${priceBox3}€`} </div> <div data-boxprice="4" data-price={`${priceBox4}`} onClick={(ev) => handleSelectedBox(ev)} className={clsx( classes.priceBox, ((selected === "4" && price === priceBox4) || price === priceBox4) && classes.priceBoxSelected )} > {`${priceBox4}€`} </div> </section> <form onSubmit={handleSubmit(onSubmit)}> <Controller name="voucherPrice" control={control} defaultValue={""} // 修改:匹配初始price的空字符串状态 rules={{ required: true }} render={({ field: { onChange, value, ref, ...field } }) => ( <Input {...field} onChange={(ev) => { handlePriceInputChange(ev); onChange(ev.target.value); // 新增:同步输入值到RHF表单字段 }} value={price} type="number" innerRef={ref} /> )} /> <p>{errors.voucherPrice?.message}</p> <Button variant="contained" sx={{ mt: 1, mr: 1 }} type="submit" > {"Continue"} </Button> </form> </div> ); } export default PriceSelection;
排查技巧
后续遇到类似提交不触发的问题,可以给handleSubmit传入第二个回调函数,直接打印校验失败的错误信息,方便快速定位问题:
<form onSubmit={handleSubmit(onSubmit, (errors) => console.log("校验失败:", errors))}>
内容的提问来源于stack exchange,提问作者Gotey
相关产品推荐
相关产品推荐

