如何在React-Hook-Form中同时实现输入验证与状态保存?
问题解决:React-Hook-Form 集成后自定义状态与onChange失效
问题根源
React-Hook-Form(RHF)的核心设计是接管表单状态管理,你手动添加的useState和onChange会和RHF的内部状态管理冲突:
register函数会自动覆盖组件的onChange属性,导致你的handleChange无法触发- RHF不会同步更新你自己定义的
stateRegister,所以console.log看不到最新值
解决方案
完全依托RHF的状态管理机制,移除自定义的useState和onChange,用RHF提供的API获取表单值:
1. 移除冗余状态与事件处理
删掉stateRegister、repassword这两个useState,以及对应的handleChange、handleConfirmPassword函数。
2. 用RHF的API获取表单值
- 使用
watch监听实时输入值 - 使用
getValues在需要时获取指定字段值 - 如需向父组件同步表单状态,可通过
watch触发回调
3. 确认密码的验证处理
给确认密码字段添加register,并通过自定义验证规则匹配密码字段值
修改后的完整代码
import * as React from 'react' import Grid from '@mui/material/Grid' import Typography from '@mui/material/Typography' import TextField from '@mui/material/TextField' import FormControlLabel from '@mui/material/FormControlLabel' import Checkbox from '@mui/material/Checkbox' import propTypes from 'prop-types' import { useForm, watch } from 'react-hook-form' export default function BasicForm(props) { const { register, formState: { errors }, getValues, } = useForm({ mode: 'all', defaultValues: { username: '', login: '', password: '', repassword: '', saveLogin: false } }) // 监听表单变化,同步给父组件 const formValues = watch() React.useEffect(() => { props.stateOfRegister(formValues) }, [formValues, props.stateOfRegister]) console.log('当前表单值:', formValues) console.log('errors: ', errors) return ( <React.Fragment> <Typography variant="h6" gutterBottom> 注册信息填写 </Typography> <Typography variant="caption" color="red" gutterBottom> 所有字段为必填项 * </Typography> <Grid container spacing={3}> <Grid item xs={12}> <TextField required id="username" name="username" label="用户名" fullWidth autoComplete="username" variant="standard" {...register('username', { required: '用户名不能为空', minLength: { value: 3, message: '用户名至少3个字符' }, maxLength: { value: 30, message: '用户名最多30个字符' }, })} helperText={errors.username?.message} /> </Grid> <Grid item xs={12}> <TextField required id="login" name="login" label="邮箱" type="email" fullWidth autoComplete="email" variant="standard" {...register('login', { required: '邮箱不能为空', pattern: { value: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, message: '请输入有效的邮箱地址', }, })} helperText={errors.login?.message} /> </Grid> <Grid item xs={12} sm={6}> <TextField required id="password" name="password" label="密码" type="password" fullWidth autoComplete="new-password" variant="standard" {...register('password', { required: '密码不能为空', pattern: { value: /^(?=.*[0-9])(?=.*[!@#$%^&*.,])[a-zA-Z0-9!@#$%^&*.,]{6,16}$/, message: '密码必须包含至少6个字符,且包含大小写字母、数字和特殊字符', }, })} helperText={errors.password?.message} /> </Grid> <Grid item xs={12} sm={6}> <TextField required id="repassword" name="repassword" label="确认密码" type="password" fullWidth autoComplete="new-password" variant="standard" {...register('repassword', { required: '请再次输入密码', validate: value => value === getValues('password') || '两次输入的密码不一致', })} helperText={errors.repassword?.message} /> </Grid> <Grid item xs={12}> <FormControlLabel control={<Checkbox color="secondary" {...register('saveLogin')} />} label="保持登录状态" /> </Grid> </Grid> </React.Fragment> ) } BasicForm.propTypes = { stateOfRegister: propTypes.func, }
关键修改点说明
- 用RHF的
defaultValues替代自定义初始状态 - 移除所有自定义
onChange,完全由register接管输入处理 - 通过
watch实时获取表单值,并通过useEffect同步给父组件 - 确认密码的验证通过
register的validate规则实现,调用getValues获取密码字段值 - 复选框也通过
register绑定,无需手动处理状态
内容的提问来源于stack exchange,提问作者Darkpsinight_2
相关产品推荐
相关产品推荐

