React Hook Form Controller 受控输入警告及表单提交异常排查
问题解决指南
1. 解决Input组件的受控/非受控警告
原因
react-hook-form默认字段初始值为undefined,Input组件直接绑定value={value}时,输入内容会让值从undefined变为字符串,触发React的受控组件警告。
修复方案
步骤1:给useForm设置默认初始值
在useForm初始化时添加defaultValues,明确字段初始状态:const { register, handleSubmit, formState: { errors }, reset, control, } = useForm({ defaultValues: { customSelect: null, // 适配react-select的空值格式 Input: "" // Input初始值设为空字符串,避免undefined } });步骤2:Input组件处理空值兜底
在Input组件的原生input标签中,给value添加空值兜底:<input // 其他属性不变 value={value || ""} // 其他属性不变 />
2. 解决提交表单无数据输出的问题
原因
Input组件没有传递onBlur事件给原生input,导致react-hook-form无法正确完成字段值的同步和校验触发。
修复方案
- 步骤1:Input组件接收并绑定onBlur
修改Input组件的props定义和原生input的绑定:// Input组件的props参数添加onBlur const Input = forwardRef( ( { label, type, value, disabled, placeholder, name, register, errors, required, validationSchema, onChange, onBlur // 新增接收onBlur }, ref ) => { // ...其他代码不变 return ( <div className="flex flex-col"> {/* ...其他代码不变 */} <input // 其他属性不变 onBlur={(e) => { e.target.style.borderColor = inputStyles.borderColor; e.target.style.borderWidth = "1px"; onBlur?.(); // 调用Controller传递的onBlur }} // 其他属性不变 /> {/* ...其他代码不变 */} </div> ); } );
3. 解决提交后错误提示不消失的问题
原因
- 默认校验模式为
onSubmit,仅在提交时校验,后续输入不会自动重新校验清除错误 reset()默认不会清除errors状态
修复方案
步骤1:设置实时校验模式
在useForm初始化时添加mode配置,让校验在输入变化时触发:const { register, handleSubmit, formState: { errors }, reset, control, } = useForm({ defaultValues: { customSelect: null, Input: "" }, mode: "onChange" // 输入变化时自动校验,实时更新错误状态 });步骤2:提交后重置表单并清除错误
修改onSubmitted函数,调用reset()时传递默认值,确保错误状态被清除:const onSubmitted = (data, e) => { console.log(data); console.log(errors.Input); reset({ customSelect: null, Input: "" }); // 显式传递默认值,确保表单和错误状态重置 };
完整修改后的关键代码片段
Form组件修改后
import { useForm, Controller } from "react-hook-form"; import CustomSelect from "../Select/Select"; import Input from "../Input/Input"; import Button from "../Button/Button"; const Form = () => { const { register, handleSubmit, formState: { errors }, reset, control, } = useForm({ defaultValues: { customSelect: null, Input: "" }, mode: "onChange" }); const onSubmitted = (data, e) => { console.log(data); console.log(errors.Input); reset({ customSelect: null, Input: "" }); }; return ( // ...原有JSX结构不变 ); };
Input组件修改后
import { forwardRef } from "react"; const Input = forwardRef( ( { label, type, value, disabled, placeholder, name, register, errors, required, validationSchema, onChange, onBlur }, ref ) => { const inputStyles = { backgroundColor: disabled ? "#f0f4f8" : "#ffffff", color: disabled ? "#6b7280" : "#000000", borderColor: disabled ? "#e5e7eb" : "#a0aec0", }; const focusStyles = { borderColor: "#2563eb", borderWidth: "2px", }; return ( <div className="flex flex-col"> <label> <span className="text-sm dark:text-gray-900">{label}</span> </label> <input type={type} name={name} className="h-9 border rounded p-2 outline-none" style={{ ...inputStyles }} value={value || ""} onChange={onChange} disabled={disabled} placeholder={placeholder} onFocus={(e) => { e.target.style.borderColor = focusStyles.borderColor; e.target.style.borderWidth = focusStyles.borderWidth; }} onBlur={(e) => { e.target.style.borderColor = inputStyles.borderColor; e.target.style.borderWidth = "1px"; onBlur?.(); }} ref={ref} /> {errors && errors[name]?.type === "required" && ( <span className="error">{errors[name]?.message}</span> )} </div> ); } ); export default Input;
内容的提问来源于stack exchange,提问作者Denyyel
相关产品推荐
相关产品推荐

