如何在react-hook-form中监听表单重置事件?
解决方案
针对react-hook-form中子组件监听表单重置并同步非注册字段状态的需求,有两种可靠方案:
方案一:自定义上下文传递重置信号
通过创建专属Context,让父组件在触发表单重置时主动通知子组件执行额外操作,这是最直观且无副作用的方案:
修改后的完整代码
import { useState, createContext, useEffect } from 'react'; import { FormProvider, useForm, useFormContext } from 'react-hook-form'; // 创建重置上下文,用于传递触发信号 const ResetContext = createContext(); const initialValues = { firstName: "empty", lastName: "empty" }; function MyForm() { const methods = useForm({ defaultValues: { ...initialValues } }); // 用数值递增作为触发信号,确保每次重置都能触发子组件的监听 const [resetTrigger, setResetTrigger] = useState(0); const onSubmit = data => { console.log(data); }; const handleReset = () => { // 先执行react-hook-form的表单重置 methods.reset({ ...initialValues }); // 更新触发信号,通知子组件同步状态 setResetTrigger(prev => prev + 1); }; return ( <ResetContext.Provider value={resetTrigger}> <FormProvider {...methods}> <CustomContent /> <button type="button" onClick={methods.handleSubmit(onSubmit)}>Submit</button> <button type="button" onClick={handleReset}>Reset</button> </FormProvider > </ResetContext.Provider> ); } function CustomContent() { const { register } = useFormContext(); const resetTrigger = useContext(ResetContext); const [isChecked, setIsChecked] = useState(false); // 监听重置信号,触发复选框状态重置 useEffect(() => { setIsChecked(false); }, [resetTrigger]); return ( <div> <input {...register('firstName')} placeholder="First Name" /> <input {...register('lastName')} placeholder="Last Name" /> <label > <input type="checkbox" checked={isChecked} onChange={() => setIsChecked((prev) => !prev)} /> <span>Check me</span> </label> </div> ); } export default MyForm;
方案二:全局自定义事件(轻量备选)
如果不想新增Context,可以利用浏览器自定义事件实现跨组件通知,适合简单场景:
修改父组件的重置逻辑
const handleReset = () => { methods.reset({ ...initialValues }); // 派发全局自定义事件 window.dispatchEvent(new CustomEvent('form-reset')); };
子组件监听事件
function CustomContent() { const { register } = useFormContext(); const [isChecked, setIsChecked] = useState(false); useEffect(() => { const handleReset = () => setIsChecked(false); // 监听自定义事件 window.addEventListener('form-reset', handleReset); // 组件卸载时移除监听 return () => window.removeEventListener('form-reset', handleReset); }, []); // ... 其余代码不变 }
为什么基于isDirty的方案无效
你之前尝试的isDirty监听方案存在两个问题:
- 若表单从未被修改过,点击重置时
isDirty始终为false,不会触发useEffect; - 若用户手动将表单字段改回初始值,
isDirty也会变为false,这会误触发复选框重置,不符合需求。
内容的提问来源于stack exchange,提问作者CongoTM
相关产品推荐
相关产品推荐

