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

react-hook-form中watch提交前不更新值,IONIC注册表单验证求助

Ionic React注册表单:解决邮箱唯一性验证与提交跳转问题

核心需求回顾

点击提交按钮「Passer à mon adhésion」时,需同时满足两个条件才跳转至下一页:

  1. 表单通过Yup的所有字段验证
  2. 输入的邮箱未在数据库中注册(userData为undefined)
    若邮箱已被使用,则在表单中显示错误提示。

问题根源分析

你之前尝试的watch/useWatch、getValues方案,核心问题是邮箱唯一性查询的时机不对:要么是提交后才触发查询(导致跳转先执行,查询结果滞后),要么是查询状态与表单验证不同步(需要两次提交才能触发错误提示)。

最优解决方案

将邮箱唯一性验证整合到React Hook Form的异步验证流程中,同时实时监听邮箱输入触发查询,确保提交时验证状态完全同步。

1. 用Yup添加异步邮箱唯一性验证规则

直接在Yup的表单校验schema中加入异步验证,让React Hook Form自动处理验证流程,无需手动判断userData:

import * as yup from 'yup';

const registrationSchema = yup.object().shape({
  email: yup.string()
    .email('请输入有效的邮箱地址')
    .required('邮箱不能为空')
    // 自定义异步验证:检查邮箱是否已注册
    .test(
      'unique-email',
      '该邮箱已被注册',
      async (email) => {
        if (!email) return true; // 空值时跳过,由required规则处理
        try {
          const response = await fetch(`/api/check-email?email=${encodeURIComponent(email)}`);
          const data = await response.json();
          return data.isAvailable; // 接口返回true表示邮箱未被注册
        } catch (err) {
          console.error('邮箱校验失败:', err);
          return false; // 网络错误时默认视为验证失败
        }
      }
    ),
  // 其他字段的校验规则...
});

2. 初始化React Hook Form并关联校验规则

使用useForm的resolver绑定Yup schema,让表单自动处理同步/异步验证:

import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';

const RegistrationForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm({
    resolver: yupResolver(registrationSchema),
    mode: 'onSubmit', // 仅在提交时触发验证(也可设为onChange实时验证)
  });

  // 提交成功后的跳转逻辑
  const onSubmit = async (data: FormData) => {
    // 能走到这里说明所有验证(包括邮箱唯一性)都通过了
    window.location.href = '/enroll'; // 或者用Ionic的useNavigate跳转
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <ion-input
        type="email"
        placeholder="邮箱地址"
        {...register('email')}
      ></ion-input>
      {/* 显示邮箱字段的错误提示 */}
      {errors.email && <ion-text color="danger">{errors.email.message}</ion-text>}

      {/* 其他表单字段... */}

      <ion-button
        type="submit"
        disabled={isSubmitting}
      >
        {isSubmitting ? '验证中...' : 'Passer à mon adhésion'}
      </ion-button>
    </form>
  );
};

export default RegistrationForm;

3. 可选:实时监听邮箱输入提前触发验证

如果希望用户输入邮箱时就实时校验唯一性,可以把mode设为onChange,或者用useWatch手动触发查询:

import { useWatch } from 'react-hook-form';

const RegistrationForm = () => {
  const { register, handleSubmit, formState: { errors, isSubmitting }, setError, clearErrors } = useForm({
    resolver: yupResolver(registrationSchema),
    mode: 'onChange',
  });

  const email = useWatch({ name: 'email' });

  useEffect(() => {
    if (!email) return;
    // 清除之前的邮箱错误
    clearErrors('email');
    
    const checkEmailUnique = async () => {
      try {
        const response = await fetch(`/api/check-email?email=${encodeURIComponent(email)}`);
        const data = await response.json();
        if (!data.isAvailable) {
          setError('email', { message: '该邮箱已被注册' });
        }
      } catch (err) {
        setError('email', { message: '邮箱校验失败,请重试' });
      }
    };

    // 防抖处理:避免输入时频繁请求
    const timeoutId = setTimeout(checkEmailUnique, 500);
    return () => clearTimeout(timeoutId);
  }, [email, setError, clearErrors]);

  // ... 其余代码不变
};

为什么之前的方案失效?

  • getValues方案:getValues同步获取字段值,但邮箱唯一性查询是异步的,第一次提交时查询还未完成,userData仍为undefined,导致提前跳转;第二次提交时查询结果已返回,才会触发错误提示。
  • watch/useWatch方案:如果仅在提交回调中触发查询,提交动作会先执行跳转,查询结果滞后返回,导致返回后再次提交才显示错误。
  • 禁用提交按钮方案:若仅在提交时检测邮箱变化,用户输入邮箱后未触发提交,按钮状态不会更新,无法实时反映验证状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:32:25