在Ionic/React中结合React Hook Forms解决提交未触控件不显示错误问题
解决Ionic 7 + React Hook Forms v7表单提交未触摸控件不显示错误的问题
问题根源
你的实现存在两个核心脱节:
- 自定义输入组件
RequiredTextInput自行维护isTouched、isValid状态,完全脱离React Hook Forms(RHF)的统一表单状态管理 - 提交表单时RHF已触发校验并更新
errors,但组件不知道表单已提交,导致未触摸控件不显示错误 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
相关产品推荐
相关产品推荐

