useEffect结合watch无法过滤表单字段变更的问题咨询
问题:react-hook-form中useEffect依赖[cityValue]无法过滤字段变更的原因
我尝试使用react-hook-form的watch hook监听city字段的变更,期望仅当city变化时触发日志输出,而name字段变更时不产生日志,但实际运行时所有表单字段变更都会触发日志,且useEffect的依赖[cityValue]未起到过滤作用,效果等同于依赖为空数组。
代码示例:
import * as React from 'react'; import { useForm } from 'react-hook-form'; export default function App() { const { watch, register } = useForm({ mode: 'all', reValidateMode: 'onBlur', }); const cityValue = watch('city', 'my city'); const nameValue = watch('name', 'my name'); // Will console the changes React.useEffect(() => { const subscription = watch((value, { name, type }) => console.log(value, name, type) ); return () => subscription.unsubscribe(); }, [cityValue]); return ( <div> <p>Start editing & look at the console how values changes :</p> <input value={cityValue} {...register('city')} /> <label>{cityValue}</label> <br /> <input value={nameValue} {...register('name')} /> <label>{nameValue}</label> <br /> </div> ); }
原因及解决方案
核心原因
你在useEffect中调用的是无参数的watch(),它会订阅所有表单字段的变更,和你设置的依赖[cityValue]无关:
watch('city')返回的city字段值变化时,会触发useEffect重新执行,但每次执行都会创建一个新的全字段订阅,所以name字段变更时依然会触发日志。[cityValue]只是控制useEffect的执行时机,不是控制watch的监听范围。就算city变化后重新订阅,新订阅依然监听所有字段,达不到只监听city的目的。- 当前写法还会导致重复订阅:每次city变化,旧订阅虽然被取消,但新订阅又会监听全字段,完全偏离需求。
正确写法
方法1:直接订阅指定字段
通过给watch()传入字段名,只监听city的变更,不需要依赖cityValue:
import * as React from 'react'; import { useForm } from 'react-hook-form'; export default function App() { const { watch, register } = useForm({ mode: 'all', reValidateMode: 'onBlur', }); const cityValue = watch('city', 'my city'); const nameValue = watch('name', 'my name'); React.useEffect(() => { // 仅订阅city字段的变更 const subscription = watch('city', (value, { name, type }) => { console.log(value, name, type); }); return () => subscription.unsubscribe(); }, [watch]); // 依赖watch实例即可 return ( <div> <p>Start editing & look at the console how values changes :</p> <input value={cityValue} {...register('city')} /> <label>{cityValue}</label> <br /> <input value={nameValue} {...register('name')} /> <label>{nameValue}</label> <br /> </div> ); }
方法2:直接监听cityValue的变化
如果只是需要在city值变化时执行逻辑,不需要使用watch的订阅回调,直接监听cityValue即可:
import * as React from 'react'; import { useForm } from 'react-hook-form'; export default function App() { const { watch, register } = useForm({ mode: 'all', reValidateMode: 'onBlur', }); const cityValue = watch('city', 'my city'); const nameValue = watch('name', 'my name'); // 仅在cityValue变化时触发 React.useEffect(() => { console.log('city changed:', cityValue); }, [cityValue]); return ( <div> <p>Start editing & look at the console how values changes :</p> <input value={cityValue} {...register('city')} /> <label>{cityValue}</label> <br /> <input value={nameValue} {...register('name')} /> <label>{nameValue}</label> <br /> </div> ); }
内容的提问来源于stack exchange,提问作者serge
相关产品推荐
相关产品推荐

