react-hook-form预填字段未触摸提交为空的原因及解决办法
问题原因
你当前的写法把自己维护的msg状态和react-hook-form的内部表单状态割裂了:
- 初始时react-hook-form内部的
message字段值为空(未设置默认值) - 你通过
fetch拿到数据后更新了msg,让输入框显示了预填内容,但这个值没有同步到react-hook-form的内部状态 - 只有当用户点击输入框(触发输入框的
onChange事件)时,register绑定的回调才会把当前msg值同步到react-hook-form的状态里,此时提交才能拿到值
解决方案
方案1:用react-hook-form的reset同步初始值(官方推荐)
移除自己维护的msg状态,让react-hook-form全权管理表单值,通过reset方法把接口返回的预填值同步到表单内部状态:
function Form() { const { register, handleSubmit, reset, formState: { errors } } = useForm<Inputs>(); // 组件挂载后请求数据并初始化表单 useEffect(() => { fetch(message) .then(r => r.text()) .then(text => { reset({ message: text }); }); }, []); const onSubmit: SubmitHandler<Inputs> = data => { console.log("submit") console.log(data) reset(); };
对应的TextField组件无需手动指定value,让register接管控制:
<TextField id="message" className='inputfield' size="small" label="Message" {...register("message", { required: true })} // 把必填规则移到register中 multiline rows={7} />
方案2:用setValue同步外部状态到表单
如果必须自己维护msg状态,可通过react-hook-form提供的setValue方法,在更新msg的同时同步到表单内部状态:
function Form() { const [msg, setMsg] = useState(""); const { register, handleSubmit, reset, setValue, formState: { errors } } = useForm<Inputs>(); useEffect(() => { fetch(message) .then(r => r.text()) .then(text => { setMsg(text); setValue("message", text); }); }, [setValue]); const onSubmit: SubmitHandler<Inputs> = data => { console.log("submit") console.log(data) reset(); };
TextField需要手动同步onChange事件:
<TextField id="message" className='inputfield' size="small" label="Message" {...register("message", { required: true })} multiline rows={7} value={msg} onChange={(e) => { setMsg(e.target.value); setValue("message", e.target.value); }} />
关键提示
react-hook-form的核心设计是让它自己管理表单状态,尽量避免混合外部state,这样能彻底避免状态不同步的问题。方案1是官方推荐的写法,代码更简洁且符合框架设计逻辑。
内容的提问来源于stack exchange,提问作者erotavlas
相关产品推荐
相关产品推荐

