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

在Ionic/React中结合React Hook Forms解决提交未触控件不显示错误问题

解决Ionic 7 + React Hook Forms v7表单提交未触摸控件不显示错误的问题

问题根源

你的实现存在两个核心脱节:

  1. 自定义输入组件RequiredTextInput自行维护isTouched、isValid状态,完全脱离React Hook Forms(RHF)的统一表单状态管理
  2. 提交表单时RHF已触发校验并更新errors,但组件不知道表单已提交,导致未触摸控件不显示错误
  3. Controller提供的field属性(包含onChange、onBlur、value)未被使用,RHF无法跟踪字段状态

解决方案:重构组件对接RHF状态

步骤1:修改RequiredTextInput,复用RHF状态

移除组件内部状态,改用RHF提供的字段状态、提交状态和错误信息:

import { IonInput } from '@ionic/react';
import { ControlField } from 'react-hook-form';

type RequiredTextInputProps = {
  label: string;
  placeholder: string;
  field: ControlField<string>; // RHF字段对象
  error?: { message: string }; // RHF错误信息
  isSubmitted: boolean; // 表单是否已提交
  onChange?: (value: string) => void; // 自定义额外逻辑
};

function RequiredTextInput({
  label,
  placeholder,
  field,
  error,
  isSubmitted,
  onChange,
}: RequiredTextInputProps) {
  // 错误显示逻辑:表单已提交 或 字段已触摸,且存在错误
  const showError = (isSubmitted || field.touched) && !!error;

  return (
    <IonInput
      placeholder={placeholder}
      value={field.value || ''}
      className={`${showError ? 'ion-invalid ion-touched' : field.touched ? 'ion-touched' : ''}`}
      type="text"
      fill="solid"
      label={label}
      labelPlacement="floating"
      helperText="Enter a non-empty value."
      errorText={showError ? error?.message : ''}
      onIonChange={(event) => {
        const inputValue = event.detail.value || '';
        field.onChange(inputValue); // 先通知RHF更新字段值
        onChange?.(inputValue); // 执行自定义逻辑
      }}
      onIonBlur={field.onBlur} // 通知RHF标记字段为已触摸
    />
  );
}

export default RequiredTextInput;

步骤2:调整父组件表单,传递RHF状态

从useForm获取isSubmitted等状态,在Controller中正确传递字段信息:

import { useForm, Controller } from 'react-hook-form';
import RequiredTextInput from './RequiredTextInput';
import { IonButton, IonContent } from '@ionic/react';

// 表单数据类型定义
type FormValues = {
  firstName: string;
};

export default function ContactForm() {
  const {
    control,
    handleSubmit,
    formState: { errors, isSubmitted },
  } = useForm<FormValues>({
    defaultValues: {
      firstName: contactInfo.lastName || '', // 用RHF初始化字段值
    },
  });

  const handleSaveAndContinue = (data: FormValues) => {
    // 处理提交逻辑
    console.log('提交数据:', data);
  };

  return (
    <IonContent>
      <form onSubmit={handleSubmit(handleSaveAndContinue)}>
        <Controller
          name="firstName"
          control={control}
          rules={{
            required: { value: true, message: "字段不能为空" },
          }}
          render={({ field }) => (
            <RequiredTextInput
              label="姓氏"
              placeholder="请输入姓氏"
              field={field}
              error={errors.firstName}
              isSubmitted={isSubmitted}
              onChange={(lastName) =>
                setContactInfo({ ...contactInfo, lastName })
              }
            />
          )}
        />

        <IonButton type="submit" className="mt-4">保存并继续</IonButton>
      </form>
    </IonContent>
  );
}

核心优化点

  • 用RHF的isSubmitted状态触发提交后的全局错误显示,解决未触摸控件不报错的问题
  • 复用RHF的field.touched状态,统一管理字段触摸状态,无需组件自行维护
  • 直接使用RHF的errors对象获取错误信息,保持校验逻辑统一
  • 通过Controller的defaultValues初始化字段,确保RHF状态与组件值同步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:01:35