如何为react-hook-form任意字段变更添加全局自定义回调?
react-hook-form 全局监听表单变更实现localStorage持久化
你不需要重写每个字段的onChange绑定逻辑,用react-hook-form本身的API做极少量封装,就能完全实现你期望的「初始化useForm时传入全局回调、任意字段变更自动触发」的效果。
方案1:封装自定义useForm,完全匹配你期望的调用方式
只需要对官方原生useForm做一层薄封装,新增全局onChange/onBlur配置项的支持,后续所有表单都可以复用这个封装:
import { useForm as useRHForm, useEffect } from 'react-hook-form'; const useForm = (config = {}) => { // 拆分出自定义的回调配置和原生useForm配置 const { onChange, onBlur, ...nativeConfig } = config; const methods = useRHForm(nativeConfig); const { watch, formState: { isDirty } } = methods; // 监听所有表单字段的值 const allFormValues = watch(); // 值变更时触发传入的全局onChange useEffect(() => { if (isDirty && typeof onChange === 'function') { onChange(allFormValues); } }, [allFormValues, isDirty, onChange]); return methods; };
封装完成后,你就可以直接按照你写的示例方式调用,注意localStorage仅支持存储字符串,存值时需要做序列化:
const App = () => { const { register, handleSubmit } = useForm({ // 初始化时直接从localStorage读取缓存值作为默认值,刷新页面自动回填 defaultValues: JSON.parse(localStorage.getItem('form_cache') || '{}'), // 任意字段变更就把全量值存到localStorage onChange: (allValues) => { localStorage.setItem('form_cache', JSON.stringify(allValues)); } }); return ( <form onSubmit={handleSubmit(data => console.log('提交数据', data))}> <input {...register('username')} placeholder="请输入用户名" /> <input {...register('email')} placeholder="请输入邮箱" /> <button type="submit">提交</button> </form> ); };
方案2:不做封装,直接用原生API实现
如果不想额外写封装逻辑,直接在业务组件内组合watch和useEffect就能实现同样效果:
import { useForm, useEffect } from 'react-hook-form'; const App = () => { const { register, handleSubmit, watch } = useForm({ defaultValues: JSON.parse(localStorage.getItem('form_cache') || '{}'), }); const allFormValues = watch(); useEffect(() => { localStorage.setItem('form_cache', JSON.stringify(allFormValues)); }, [allFormValues]); // 表单其余逻辑正常编写即可,不需要修改任何字段的onChange绑定 return ( <form onSubmit={handleSubmit(data => console.log('提交数据', data))}> <input {...register('username')} placeholder="请输入用户名" /> <input {...register('email')} placeholder="请输入邮箱" /> <button type="submit">提交</button> </form> ); };
实用优化点
- 性能优化:如果表单字段多、输入频繁,可以给存储逻辑加防抖,避免每次按键都操作localStorage:
import { debounce } from 'lodash-es'; const debouncedSave = debounce((values) => { localStorage.setItem('form_cache', JSON.stringify(values)); }, 300); // 回调中调用防抖方法即可 onChange: (allValues) => debouncedSave(allValues) - 敏感字段过滤:如果表单包含密码、验证码这类不需要持久化的字段,在存值前过滤掉对应字段即可
- 存储时机调整:如果不需要每次输入都存,只想在字段失焦时存,可以把
watch的触发时机改为blur模式,或者监听formState里的touchedFields变化触发存储 - 提交后清空缓存:表单提交成功后调用
localStorage.removeItem('form_cache')即可清除持久化的草稿数据
内容的提问来源于stack exchange,提问作者Mike Kokadii
相关产品推荐
相关产品推荐

