Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: register is not a function using React Hook Form in React

The Error Message: Error Message: If i dont use the Inputs inside div then it works perfectly but when i use Input inside div it shows me this error.
I wanted to keep the hook related stuff separated so it look clean.
why does it only works when its not inside a div?

Login.tsx

import { useHistory } from "react-router-dom";
import { useForm } from "react-hook-form";

import useAuth from "./../hooks/useAuth";
import { Form, Input } from "../components/FormGroup";
import MacNav from "../components/MacNav";

import { loginActionUrl } from "./../services/ApiLinks";
import {
  fetchPostResopnse,
  successPopUp,
  errorPopUp,
} from "./../services/FormHelper";

type Tinputs = {
  username: string;
  password: string;
};

function Login() {
  const auth = useAuth();
  const history = useHistory();
  const methods = useForm<Tinputs>();

  const onSubmit = async (data: Tinputs) => {
    const result = await fetchPostResopnse(loginActionUrl, data);

    if (result.isAuth) {
      successPopUp("Credentials Matched", () => {
        auth.signIn(result);
        history.push("/admin/dashboard");
      });
    } else {
      errorPopUp("Credentials Does Not Matched");
    }
  };

  return (
    <div>
      <MacNav />

      <div className="section-secondary">
        <div className="container">
          <div className="contact-form-wrapper">
            <div className="title-lg text-center">Enter Your Credentials</div>
            <Form formMethods={methods} handler={onSubmit} submitBtn="Submit">
             {/*If i dont use Input inside div it works*/}
              <div>
                <Input name="username" rule={{ required: true }} />
              </div>
              <Input name="password" rule={{ required: true }} />
            </Form>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Login;

I have wrote the form components here. FormGroup.tsx

import React from "react";

const Form = ({ children, formMethods, handler, submitBtn }: any) => {
  return (
    <form onSubmit={formMethods.handleSubmit(handler)}>
      {React.Children.map(children, (child) => {
        return child.props.name ? (
          <div>
            {React.createElement(child.type, {
              ...{
                ...child.props,
                register: formMethods.register,
                key: child.props.name,
              },
            })}
            {child.props?.rule && formMethods.errors[child.props.name] && (
              <div className="text-danger">
                *
                {formMethods.errors[child.props.name].message
                  ? formMethods.errors[child.props.name].message
                  : `${child.props.name} is required`}
              </div>
            )}
          </div>
        ) : (
          child
        );
      })}
      {submitBtn && <button type="submit">{submitBtn}</button>}
    </form>
  );
};

const Input = ({ register, name, label, rule, ...rest }: any) => {
  label = label ? label : name?.charAt(0).toUpperCase() + name?.slice(1);
  return (
    <div>
      <label htmlFor={name}>{label}</label>
      <input name={name} ref={register(rule)} {...rest} />
    </div>
  );
};

const Textarea = ({ register, name, label, rule, ...rest }: any) => {
  label = label ? label : name?.charAt(0).toUpperCase() + name?.slice(1);
  return (
    <div>
      <label htmlFor={name}>{label}</label>
      <textarea name={name} ref={register(rule)} {...rest}></textarea>
    </div>
  );
};

const SubmitButton = ({ name, ...rest }: any) => {
  return (
    <button type="submit" {...rest}>
      {name}
    </button>
  );
};

export { Form, Input, Textarea, SubmitButton };


  [1]: https://i.sstatic.net/PvEUA.png
like image 910
antoninislam Avatar asked Nov 19 '25 07:11

antoninislam


1 Answers

Hello according to your code, what happened it's expected

the div doesn't have name so according to this code

{React.Children.map(children, (child) => {
        return child.props.name ? (
          <div>
            {React.createElement(child.type, {
              ...{
                ...child.props,
                register: formMethods.register,
                key: child.props.name,
              },
            })}
            {child.props?.rule && formMethods.errors[child.props.name] && (
              <div className="text-danger">
                *
                {formMethods.errors[child.props.name].message
                  ? formMethods.errors[child.props.name].message
                  : `${child.props.name} is required`}
              </div>
            )}
          </div>
        ) : (
          child
        );
      })}

And the below child

<div>
  <Input name="username" rule={{ required: true }} />
/div>

The Input component will be rendrered without register prop, so when it will try to call it here, however it's value is undefined, what will cause an error

ref={register(rule)}

I suggest to create a new component

const InputWithDiv = (props) => (
<div>
  <Input rule={{ required: true }}  {..props} />
/div>
);

and use it like below

<Form formMethods={methods} handler={onSubmit} submitBtn="Submit">
  <InputWithDiv name="username" />
  <Input name="password" rule={{ required: true }} />
</Form>
like image 151
ARZMI Imad Avatar answered Nov 22 '25 02:11

ARZMI Imad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!