6

I use the following code to create a login page with form validation:

import React from 'react';
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
import { useForm } from 'react-hook-form';

class SignIn extends React.Component {
  
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => console.log(data);
console.log(errors);

  render() {
    return (
      <div>
        <Form onSubmit={handleSubmit(onSubmit)}>

            <Label>Email : </Label>
            <Input type="email" placeholder="email" name="email" ref={register({required: true, pattern: /^\S+@\S+$/i})}></Input>

            <Label>Password : </Label>
            <Input type="password" placeholder="password"  name="password" ref={register({required: true, min: 8, maxLength: 20})}></Input>

        </Form>
      </div>
    );
  }
}


export default SignIn;

and I have a problem using react-hook-form inside the Class Component
My question, if it's possible, is: How to use the react-hook-form with Class Component without rewriting the code to the hook version?

1
  • If you still have the problem look at my answer, I even added a live sandbox! Commented Feb 22, 2021 at 13:25

6 Answers 6

8

You can't use hooks in react class components. The class that you provide looks small and I think that you can easily rewrite it to functional component. Perhaps you don't want to, you can provide hoc with useForm hook that wraps your class component.

export const withUseFormHook = (Component) => {
    return props => {
        const form = useForm();
        return <Component {...props} {...form} />
    }       
}

And in you SignIn component simply do:

export default withUseFormHook(SignIn);
Sign up to request clarification or add additional context in comments.

6 Comments

I am just a beginner with React.js, your answer looks like something new for me
But I think that it's similar to my answer. my answer is creating a hook Component and use it inside the Class Component, and your answer is the reverse. that's it?
Not really, in your answer you created new functional Component that can replace class Component. I will comment your answer with a little bit more simple solution than yours.
I used somethin called Higher Order Component, its a bit more advanced React pattern, but if you want just read about it, and it's usage in an official docs: reactjs.org/docs/…
@piotrruss Thanks, based on your answer I could solve my issue.
|
2

The best and easiest way will be to change class Component, to a functional Component and use the useForm hook. Below you can find the example code:

import React from 'react'

import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
import { useForm } from 'react-hook-form';

const SignIn = () => {

  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => console.log(data);
  console.log(errors);

  return (
    <>
      <div>
        <Form onSubmit={handleSubmit(onSubmit)}>

        <Label>Email : </Label>
        <Input type="email" placeholder="email" name="email" ref={register({required: true, pattern: /^\S+@\S+$/i})}></Input>

        <Label>Password : </Label>
        <Input type="password" placeholder="password"  name="password" ref={register({required: true, min: 8, maxLength: 20})}></Input>

        </Form>
      </div>
    </>
  )}

export default SignIn;

2 Comments

Not a good idea. Sometimes we need to use components due to their events!
In fact this a big reason in my side to expect something will replace React (not Angular nor Vue). I was already working with dozens of examples to understand React and someday I hit the wall of "you cannot use this in a class component". For me, a class component is really useful in terms of abstraction and hierarchies. For example, I manage diferent implementations using polymorphism. I have seen auth implementations that could be easier using inheritance of a Route component, but most examples rewrite it in a function, which for me smells like a bad practice
2

After searching more and more I used this solution :
Creating a separate file with the hook version :

import React from 'react'

import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
import { useForm } from 'react-hook-form';

const SignInHook = () => {

    const { register, handleSubmit, errors } = useForm();
    const onSubmit = data => console.log(data);
    console.log(errors);



    return (
    <>
      <div>
        <Form onSubmit={handleSubmit(onSubmit)}>

            <Label>Email : </Label>
            <Input type="email" placeholder="email" name="email" ref={register({required: true, pattern: /^\S+@\S+$/i})}></Input>

            <Label>Password : </Label>
            <Input type="password" placeholder="password"  name="password" ref={register({required: true, min: 8, maxLength: 20})}></Input>

        </Form>
      </div>
    </>
   )
}

export default SignInHook

And Use it inside my Class Component:

import React from 'react';
import SignInHook from './SignInHook';

class SignIn extends React.Component {
  
  render() {
    return (
      <div>
        <SignInHook></SignInHook>
      </div>
    );
  }
}


export default SignIn;

5 Comments

You can totally remove SignIn component and change SignInHook -> SignIn, update import path wherever you import SignIn and it will work ;)
I am still sticking to the Class method that’s why. I will try to use your solution also.
I see your edit. I suggest to use it as a new answer. It's better to have a question with more than one useful answer.
I am new here so I don't know a lot about the rules. If it's good to use your edit as a new answer then it's okay, if not I will approve your edit.
I was a little bit lazy :P I will post an answer
1

From the react-hook-form documentation:

Does it work with Class Components?

No, not out of the box. If you wanted to do this, you could build a wrapper around it and use it in your Class Component.

https://react-hook-form.com/faqs#DoesitworkwithClassComponents

Comments

0

I had the same issue but at the end I could solve it like this:

import React from "react";
import ReactDOM from "react-dom";
import { useForm } from "react-hook-form";

import "./styles.css";

class Login extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false
    };
    this.onSubmit = this.onSubmit.bind(this);
  }

  onSubmit(data) {
    console.log(data);
  }

  render() {
    const { register, handleSubmit, errors } = this.props;
    return (
      <form onSubmit={handleSubmit(this.onSubmit)}>
        <label>Example</label>
        <input name="example" defaultValue="test" ref={register} />
        <label>ExampleRequired</label>
        <input
          name="exampleRequired"
          ref={register({ required: true, maxLength: 10 })}
        />
        {errors.exampleRequired && <p>This field is required</p>}
        <input type="submit" />
      </form>
    );
  }
}

function App(props) {
  const form = useForm();
  return <Login {...props} {...form} />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Here is the live sandbox.

1 Comment

I have opened an issue but at the end in a discussion the solution discovered: github.com/react-hook-form/react-hook-form/discussions/4258
0

If you use the following code it works:

class SignIn extends React.Component {
...
  render() {
    const {
      register,
      formState: { errors },
      handleSubmit } = (() => useForm({ mode: "onChange" }))();
    return (...);
  }
}

is it a good practice do it?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.