You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用react-hook-form实现密码与确认密码的校验?

React Hook Form 密码确认校验统一错误展示方案

问题描述

使用React Hook Form开发注册功能时,卡在密码与确认密码的校验环节。查阅资料大多用Yup实现校验,但希望不用Yup,且让确认密码的错误提示和其他输入框保持一致(通过error={}和helperText展示,而非Toast或console.log)。

解决方案

核心是利用React Hook Form的watch方法监听密码输入,在确认密码的register规则中添加自定义校验逻辑,将错误信息存入errors对象,从而复用现有错误展示逻辑。

修改后的完整代码:

import React from 'react'
import TuaLogo from '../../assets/tua.png'
import { useForm } from 'react-hook-form'

const USER_REGEX = /^[A-z][A-z0-9-_]{3,23}$/;
const PWD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%]).{8,24}$/;
const ID_REGEX = /^[0-9]{10}$/;

const Register = () => {
  // 解构watch方法,用于监听password字段实时值
  const { register, handleSubmit, watch, formState: { errors } } = useForm()

  // 监听password输入值
  const password = watch('password')

  const onSubmit = (data) => {
    // 校验已在字段注册阶段完成,无需手动判断密码一致性
    console.log(data)
  }

  return (
    <Container>
      <Box 
        sx={{display:'flex',
            alignItems:'center',
            justifyContent:'center',
            width: '100%', 
            height: '100vh'}}>
        <Box sx={{display:'flex', borderRadius: '20px', alignItems:'center', justifyContent: 'center', height: '900px', width: '400px', flexDirection: 'column', padding: '20px', boxShadow: 3}}>
          <Box sx={{display: 'flex', alignItems:'center', justifyContent:'center', padding: '20px',width: '150px' }}>
            <Box component="img" sx={{width: '100%', height: '100%', objectFit: 'contain'}} src={TuaLogo}></Box>
          </Box>
          <Typography my={4} sx={{ typography: {xs: 'body1', md: 'h5'}}}>E-Benta || TUA-MARKETPLACE</Typography>
          <form onSubmit={handleSubmit(onSubmit)} style={{width: '100%', display: 'flex', flexDirection:'column', gap: '20px'}}>
            <TextField   
              variant="outlined"
              name="username"
              required
              label="Username"
              fullWidth
              autoComplete='username'
              autoFocus
              {...register('username', {required: "Required", pattern: {value: USER_REGEX, message: "Username should be 3-16 characters and shouldn't include any special character!" }})}
              error={!!errors?.username}
              helperText={errors?.username ?errors.username.message: null}
            />
            <TextField   
              variant="outlined"
              name="email"
              label="Email"
              required
              fullWidth
              type="email"
              autoComplete='email'
              autoFocus
              {...register('email', {required: "Required", pattern: { message: "It should be a valid email address!" }})}
              error={!!errors?.email}
              helperText={errors?.email ?errors.email.message: null}
            />
            <TextField   
              variant="outlined"
              name="studentid"
              label="Student ID"
              required
              fullWidth
              type="text"
              autoComplete='text'
              autoFocus
              {...register('studentid', {required: "Required", pattern: {value: ID_REGEX,  message: "Please Enter your Student ID properly" }})}
              error={!!errors?.studentid}
              helperText={errors?.studentid ? errors.studentid.message: null}
            />
            <TextField   
              variant="outlined"
              name="password"
              label="Password"
              required
              fullWidth
              type="password"
              autoComplete='password'
              autoFocus
              {...register('password', {required: "Required", pattern: {value: PWD_REGEX,  message: "Password should be 8-24 characters and include at least 1 letter, 1 number and 1 special character!" }})}
              error={!!errors?.password}
              helperText={errors?.password ? errors.password.message: null}
            />
            <TextField   
              variant="outlined"
              name="password1"
              label="Confirm Password"
              required 
              fullWidth 
              type="password"
              autoComplete='password'
              autoFocus
              {...register('password1', {
                required: "Required",
                // 自定义校验规则,对比watch到的password值
                validate: (value) => {
                  return value === password || "Password does not match"
                }
              })}
              error={!!errors?.password1}
              helperText={errors?.password1 ? errors.password1.message: null}
            />
            <Button type="submit" variant="contained">Register</Button>
          </form>
        </Box>
      </Box>
    </Container>
  )
}

export default Register

关键修改说明

  • 新增watch方法监听password字段的实时输入值,用于确认密码的校验对比
  • 调整确认密码的register规则:移除错误的pattern嵌套结构,改用validate字段实现自定义校验,校验不通过时直接返回错误信息字符串
  • 删除onSubmit中手动判断密码一致性的逻辑,因为校验已提前在字段注册阶段完成
  • 移除了不再需要的toast依赖

修改后,确认密码的错误会自动存入errors.password1,和其他输入框的错误展示逻辑完全统一,无需额外处理。

内容的提问来源于stack exchange,提问作者Stykgwar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:46:06