我正在使用 react-hook-form 来验证我的输入,但是在将输入提取到它自己的组件后我无法让它工作

I'm using react-hook-form to validate my input but I can't get it to work after extracting the input to its own component

我有一个 Form.js 组件,它 return 是一个表单元素。此表单元素包含一个 FormGroup 组件,该组件采用 inputType、inputName、inputPlaceholder 等道具,并在 return 中呈现带有标签的输入字段。我正在使用 react-hook-form 来验证输入,但在将输入提取到单独的组件后我无法让它工作。在我的原始代码中,我在验证失败时出现错误,但是在提取标签并输入到他们自己的组件中后,它停止工作了。

我原来的工作代码是这样的:

import { useState } from 'react';
import { useForm } from 'react-hook-form';
import FormGroup from './FormGroup';

const Form = () => {
    const { register, handleSubmit, formState: { errors } } = useForm();

    const onSubmit = async (data) => {
        console.log(data)
    };

    return (
        <form className="form-container" onSubmit={handleSubmit(onSubmit)} autoComplete="off" noValidate>
            <div className="form-group">
                <label className="form-label" htmlFor="firstName">
                    <p>First Name</p>
                    <p className="input-error">{errors.firstName && errors.firstName.message}</p>
                </label>
                <input type="text" name="firstName" placeholder="First Name" {...register("firstName", { required: 'Required ' })} />
            </div>

            <div className="form-group">
                <button type="submit">Submit</button>
            </div>
        </form>
    );
}

export default Form

然后我改成了:

import { useState } from 'react';
import { useForm } from 'react-hook-form';
import FormGroup from './FormGroup';

const Form = () => {
    const { register, handleSubmit, formState: { errors } } = useForm();

    const onSubmit = async (data) => {
        console.log(data)
    };

    return (
        <form className="form-container" onSubmit={handleSubmit(onSubmit)} autoComplete="off" noValidate>
            <FormGroup
                inputType="text"
                inputName="firstName"
                inputPlaceholder="First Name">
            </FormGroup>

            <div className="form-group">
                <button type="submit">Submit</button>
            </div>
        </form>
    );
}

export default Form

然后我提取标签并输入到:

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

const FormGroup = (props) => {
    const { register, formState: { errors } } = useForm();

    return (
        <div className="form-group">
            <label className="form-label" htmlFor={props.inputName}>
                <p>{ props.inputPlaceholder }</p>
                <p className="input-error">{errors.firstName && errors.firstName.message}</p>
            </label>
            <input type={props.inputType} name={props.inputName} placeholder={props.inputPlaceholder} {...register(props.inputName, { required: true })} />
        </div>
    );
}

export default FormGroup

问题

您有多个 useForm 挂钩实例。

解决方案

仅在 Form 组件上使用 useForm 挂钩,并将 errors 对象和 register 方法作为 props 传递给 FormGroup

表单组件

import { useState } from 'react';
import { useForm } from 'react-hook-form';
import FormGroup from './FormGroup';

const Form = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const onSubmit = async (data) => {
    console.log(data);
  };

  return (
    <form
      className="form-container"
      onSubmit={handleSubmit(onSubmit)}
      autoComplete="off"
      noValidate
    >
      <FormGroup
        inputType="text"
        inputName="firstName"
        inputPlaceholder="First Name"
        register={register}
        errors={errors}
      ></FormGroup>

      <div className="form-group">
        <button type="submit">Submit</button>
      </div>
    </form>
  );
};

export default Form;

FormGroup 组件

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

const FormGroup = (props) => {
  return (
    <div className="form-group">
      <label className="form-label" htmlFor={props.inputName}>
        <p>{props.inputPlaceholder}</p>
        <p className="input-error">
          {props.errors.firstName && props.errors.firstName.message}
        </p>
      </label>
      <input
        type={props.inputType}
        name={props.inputName}
        placeholder={props.inputPlaceholder}
        {...props.register(props.inputName, { required: true })}
      />
    </div>
  );
};

export default FormGroup;

文档中推荐的方法如下:

useFormContext This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. https://react-hook-form.com/api/useformcontext

const Form = () => {
  const methods = useForm();
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = methods;

  const onSubmit = async (data) => {
    console.log(data);
  };

  return (
    <FormProvider {...methods} > 
      <form
        className="form-container"
        onSubmit={handleSubmit(onSubmit)}
        autoComplete="off"
        noValidate
      >
        <FormGroup
          inputType="text"
          inputName="firstName"
          inputPlaceholder="First Name">
        </FormGroup>

        <div className="form-group">
          <button type="submit">Submit</button>
        </div>
      </form>
    </FormProvider>
  );
};
const FormGroup = (props) => {
  const { register, errors } = useFormContext(); // retrieve all hook methods from parent
  return (
    <div className="form-group">
      <label className="form-label" htmlFor={props.inputName}>
        <p>{props.inputPlaceholder}</p>
        <p className="input-error">
          {errors.firstName && errors.firstName.message}
        </p>
      </label>
      <input
        type={props.inputType}
        name={props.inputName}
        placeholder={props.inputPlaceholder}
        {register(props.inputName, { required: true })}
      />
    </div>
  );
};

export default FormGroup;