React-hook-form问题:表单提交后错误消息不显示,需手动刷新
问题描述
使用react-hook-form结合yup做表单字段校验,通过<ErrorMessage>组件展示多条错误消息。遇到的问题:提交表单后立即在字段中输入无效内容,错误消息无法显示;但提交按钮会被禁用,说明校验逻辑已经触发,只是错误消息没渲染出来。手动刷新页面后,错误消息又能正常显示。
原始代码片段
import React, { useState } from "react"; import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { ErrorMessage } from "@hookform/error-message"; import validationSchema from "../validations/validationSchema"; export default function Report(props) { const { register, handleSubmit, formState: { errors, isValid }, } = useForm({ mode: "onBlur", // reValidateMode: "onChange", criteriaMode: "all", resolver: yupResolver(validationSchema), defaultValues: { closedBugs: "", }, }); const [state, setState] = useState({ closedBugs: "", reportedIncidents: "", reportedBugs: "", }); const onFormSubmit = (data, event) => { event.preventDefault(); props.onSubmit(state); }; // 补全原代码缺失的handleChange函数 const handleChange = (key, value) => { setState({ ...state, [key]: value, }); }; const modifyBugsValues = (value) => { if (value === "") { // 为空时返回undefined,让yup触发必填校验 return undefined; } else { // 替换逗号为点,让yup识别为数字进行整数校验 value = value.replace(/,/g, "."); return value; } }; return ( <div className="container"> <div className="ui segment report"> <form onSubmit={handleSubmit(onFormSubmit)} className="ui form"> <h4 className="ui dividing header">Project information</h4> <h4 className="ui dividing header">Bug metrics</h4> <div className="three fields"> <div className="field mandatory-metric"> <label>closed bugs during month</label> <div className="field"> <input type="text" {...register("closedBugs", { setValueAs: modifyBugsValues, })} onChange={(e) => handleChange(e.target.name, e.target.value)} name="closedBugs" placeholder="1" required /> <ErrorMessage errors={errors} name="closedBugs" render={({ messages }) => { console.log("Messages" + JSON.stringify(messages)); return ( messages && Object.entries(messages).map(([type, message]) => ( <p className="error" key={type}> {message} </p> )) ); }} /> </div> </div> </div> <button type="submit" className="ui secondary large button" data-cy="submitBtn" disabled={!isValid} tabIndex={0} > Submit report </button> </form> </div> </div> ); }
问题原因与修复方案
核心问题
你同时使用了react-hook-form的内置状态管理和自定义本地useState,两者状态不同步:提交表单后,react-hook-form的内部状态已标记为提交状态,但自定义的onChange仅更新本地state,未同步到react-hook-form的内部状态,导致errors对象无法及时更新,<ErrorMessage>组件拿不到最新错误信息。另外,当前mode: "onBlur"和注释掉的reValidateMode设置,也导致输入内容变化时无法实时触发校验更新错误。
具体修复步骤
移除本地state和自定义onChange
react-hook-form已内置完整的表单状态管理,无需自行维护state和handleChange,提交时直接使用react-hook-form返回的校验后data即可。开启实时校验模式
设置reValidateMode: "onChange",让输入内容变化时实时触发校验,确保errors对象及时更新,错误消息同步显示。移除input上的required属性
yup的校验规则已包含必填校验,重复设置required会导致逻辑冲突。
修复后的代码
import React from "react"; import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { ErrorMessage } from "@hookform/error-message"; import validationSchema from "../validations/validationSchema"; export default function Report(props) { const { register, handleSubmit, formState: { errors, isValid }, } = useForm({ mode: "onBlur", reValidateMode: "onChange", // 开启输入时实时校验 criteriaMode: "all", resolver: yupResolver(validationSchema), defaultValues: { closedBugs: "", reportedIncidents: "", reportedBugs: "", }, }); const onFormSubmit = (data) => { // 直接使用react-hook-form返回的校验后数据 props.onSubmit(data); }; const modifyBugsValues = (value) => { if (value === "") { return undefined; } else { return value.replace(/,/g, "."); } }; return ( <div className="container"> <div className="ui segment report"> <form onSubmit={handleSubmit(onFormSubmit)} className="ui form"> <h4 className="ui dividing header">Project information</h4> <h4 className="ui dividing header">Bug metrics</h4> <div className="three fields"> <div className="field mandatory-metric"> <label>closed bugs during month</label> <div className="field"> <input type="text" {...register("closedBugs", { setValueAs: modifyBugsValues, })} name="closedBugs" placeholder="1" /> <ErrorMessage errors={errors} name="closedBugs" render={({ messages }) => { return ( messages && Object.entries(messages).map(([type, message]) => ( <p className="error" key={type}> {message} </p> )) ); }} /> </div> </div> </div> <button type="submit" className="ui secondary large button" data-cy="submitBtn" disabled={!isValid} tabIndex={0} > Submit report </button> </form> </div> </div> ); }
内容的提问来源于stack exchange,提问作者mismas
相关产品推荐
相关产品推荐

