最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin11浏览0评论

I have a Form.js ponent which returns a form element. This form element contains a FormGroup ponent which takes props such as inputType, inputName, inputPlaceholder and in return renders an input field with a label. I am using react-hook-form for the validation of the input but I can't get it to work after extracting the input to a separate ponent. In my original code, I had my errors appear when the validation failed, but after extracting the label and input into their own ponent, this stopped working.

My original working code looks like this:

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

Then I changed it to:

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

And I extracted the label and input into:

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

I have a Form.js ponent which returns a form element. This form element contains a FormGroup ponent which takes props such as inputType, inputName, inputPlaceholder and in return renders an input field with a label. I am using react-hook-form for the validation of the input but I can't get it to work after extracting the input to a separate ponent. In my original code, I had my errors appear when the validation failed, but after extracting the label and input into their own ponent, this stopped working.

My original working code looks like this:

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

Then I changed it to:

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

And I extracted the label and input into:

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
Share Improve this question asked Apr 18, 2021 at 3:28 OnyxOnyx 5,78210 gold badges52 silver badges119 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

The Problem

You have multiple instances of the useForm hook.

Solution

Use the useForm hook only on the Form ponent and pass the errors object and register method as props to FormGroup

Form Component

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 Component

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;

The remended approach from the Documentation is as follows:

useFormContext This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would bee inconvenient to pass the context as a prop. https://react-hook-form./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;

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论