React Hook Form表单数据无法传递问题排查与解决求助
React Hook Form提交数据全为undefined的问题排查与修复
使用React Hook Form进行表单验证时,提交表单后onSubmit接收的data所有字段均为undefined,相关代码及修复方案如下:
表单组件代码
<form onSubmit={handleSubmit(onSubmit)}> <FormGroup className="mb-3"> <FormText>Full Name</FormText> <Input id="fullName" className="input-transparent pl-3" type="text" style={{ border: inputError ? "1px solid red" : "" }} name="fullName" placeholder="Henry" onChange={(e) => handleChange(e, setFormData)} {...register("fullName", { name: "fullName" })} defaultValue={fullName} /> {errors.fullName && <small>This field is required</small>} </FormGroup> <FormGroup className="my-3"> <FormText>Email</FormText> <Input id="email" className="input-transparent pl-3" type="text" name="email" placeholder="henrymonk@mail.com" onChange={(e) => handleChange(e, setFormData)} {...register("email", { name: "email" })} defaultValue={email} /> {errors.email && <small>This field is required</small>} </FormGroup> <FormGroup className="my-3"> <FormText>Phone Number</FormText> <Input id="phone" className="input-transparent pl-3" type="text" name="phone" placeholder="+123456789" onChange={(e) => handleChange(e, setFormData)} {...register("phone", { name: "phone" })} defaultValue={phone} /> {errors.phone && <small>This field is required</small>} </FormGroup> <FormGroup className="my-3"> <div className="d-flex justify-content-between"> <FormText></FormText> {/* <Link to="/error">Forgot password?</Link> */} </div> <FileUploader content={`Upload Photo`} icon={`image`} onChange={handleFileSelect} /> </FormGroup> <FormGroup className="my-3"> <div className="d-flex justify-content-between"> <FormText>Password</FormText> <Link to="/error">Forgot password?</Link> </div> <InputGroup> <Input id="password" className="input-transparent pl-3" style={{ borderRight: "none" }} type={showPassword === true ? 'text' : 'password'} name="password" placeholder="Place your password here" onChange={(e) => handleChange(e, setFormData)} {...register("password", { name: "password" })} defaultValue={password} /> <Button color="white" onClick={handleShowPassword} style={{ margin: 0, padding: "0px 20px", justifyContent: "center", alignItems: "center", borderTopLeftRadius: 0, borderBottomLeftRadius: 0, borderRight: "1px solid #6b859e65", borderBlock: "1px solid #6b859e65", }} > <i className={showPassword === false ? `eva eva-eye-outline` : `eva eva-eye-off-outline`} /> </Button> </InputGroup> {errors.password && <small>This field is required</small>} </FormGroup> <div className="bg-widget d-flex justify-content-center"> <Button className="rounded-pill my-3" type="submit" color="secondary-red" > Sign Up </Button> </div> <p className="dividing-line my-3"> Or </p> <div className="d-flex align-items-center my-3"> <p className="social-label mb-0">Login with</p> <div className="socials"> <a href="https://flatlogic.com/"> <GoogleIcon /> </a> <a href="https://flatlogic.com/"> <GithubIcon /> </a> </div> <Link to="/login">Enter your Cradev account</Link> </div> </form>
相关函数与状态
const [formData, setFormData] = useState({ email: '', fullName: '', password: '', phone: '', }); const onSubmit = async (data) => { try { console.log("data", data) await dispatch(registerUser(data)).unwrap(); // props.history.push("/template"); } catch (error) { const errorMessages = error?.errors?.map((err) => err.msg); toast.error(errorMessages.join("\n"), { theme: "colored", }); } }; const handleChange = (event, setValue) => { const { name, value } = event.target; console.log(formData) setValue((prevState) => ({ ...prevState, [name]: value })); };
问题原因
- 模式冲突:同时混用React Hook Form的
register(非受控模式)和自定义useState+onChange(受控模式),手动添加的onChange会覆盖register绑定的监听逻辑,导致React Hook Form无法捕获输入值。 register参数错误:register("fullName")已自动设置name属性,无需额外传{ name: "fullName" };且代码中先写自定义onChange再展开register,若register返回的对象包含onChange会被覆盖,阻断表单状态跟踪。- 默认值配置不当:单独给每个输入框设
defaultValue不符合React Hook Form的非受控模式规范,应在useForm初始化时统一设置defaultValues。 - 自定义组件ref传递问题:若
Input是自定义组件,未正确将ref传递给内部原生input元素,会导致register无法获取DOM元素跟踪值变化。
修复方案
方案一:完全使用React Hook Form非受控模式(推荐)
移除自定义状态和handleChange,让React Hook Form全权管理表单:
- 初始化
useForm时设置默认值:
const { register, handleSubmit, formState: { errors } } = useForm({ defaultValues: { email: '', fullName: '', password: '', phone: '', } });
- 修改输入框,移除
onChange、defaultValue和手动name:
<Input id="fullName" className="input-transparent pl-3" type="text" style={{ border: inputError ? "1px solid red" : "" }} placeholder="Henry" {...register("fullName", { required: true })} />
(其他输入框同理调整)
- 直接使用
onSubmit接收的data即可,无需维护自定义状态。
方案二:使用受控模式(配合Controller组件)
若需保留自定义状态,用Controller包裹输入框实现状态同步:
- 初始化
useForm关联自定义状态:
const { control, handleSubmit, formState: { errors } } = useForm({ defaultValues: formData });
- 用
Controller包裹输入框:
<Controller name="fullName" control={control} rules={{ required: true }} render={({ field }) => ( <Input id="fullName" className="input-transparent pl-3" type="text" style={{ border: inputError ? "1px solid red" : "" }} placeholder="Henry" {...field} onChange={(e) => { field.onChange(e); // 同步React Hook Form状态 setFormData(prev => ({ ...prev, fullName: e.target.value })); // 同步自定义状态 }} /> )} />
额外注意点
- 自定义
Input组件需确保能传递value、onChange、ref到内部原生input元素,否则register或Controller无法正常工作。 - 验证规则可直接写在
register或Controller的rules属性中。
内容的提问来源于stack exchange,提问作者Mohamed Amine Boudagga
相关产品推荐
相关产品推荐

