DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for The last react form library you will ever need
Ivan
Ivan

Posted on

The last react form library you will ever need

It’s been a while so I thought I would share a quick guide for my favorite form library, the mighty react-hook-form.

Instead of just showing you how to use the library, let’s do a little experiment that will showcase its main advantage.

A matter of performance

We have this simple form, two inputs and a submit button.

import { useState } from "react";

import "./styles.css";

export default function App() {

  return (
    <div className="App">
      <h1>Form</h1>
      <form>
        <label htmlFor="name">name</label>
        <input
          id="name"
          type="text"
        />
        <label htmlFor="age">age</label>
        <input
          id="age"
          type="number"
        />
        <button type="submit">submit</button>
      </form>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

The state approach

First, we’ll take the popular approach when making controlled forms in react, using state.

Let's create two states, one for the name and another one for the age and use them to control the value of the inputs.

We will also add an onSubmit function that will set and then display the result values.

For our little experiment we want to know the amount of re-renders that are happening under the hood. Outside the component let’s add a variable that will store the number of rerenders.

Final result!

Open the sandbox to see the code in action

Ok, that's a lot of rerenders :(

We won’t notice any performance issues in this small form, but the reality is that the current approach is not very scalable, if we keep adding inputs we will notice some important performance issues.

The react-hook-form approach

Time for react-hook-form to enter the ring.

entering ring

Let’s try to replicate the same form with this library.

The useForm hook is all we need, spreading the register function and taking care of the submit with the handleSubmit function.

This all makes sense when you see it, here it is.

Open the sandbox to see the code in action

Only one lonely render, the initial one.

You can probably already tell the advantages of react-hook-form and how it will help scale your forms much better.

How?

So how does it track the values without needing to re render.

In two concepts, ref and uncontrolled inputs.

In our first form we rely on state to keep track of the values in our form, so every time the we need to update the values, state needs to be updated as well, causing a re render. react-hook-form uses ref instead, which lets us store the values and update them without causing a re render. We don’t need to control the value of the input with this approach, so that’s why we say the inputs are uncontrolled.

Wrapping up

Performance is the main feature of react-hook-form, but there is a lot more that you can see and explore by yourself, like validation and error handling.

For example

I know some of you are about to write a comment saying this validation can be done natively with the input props. That is true, but the moment you need any customization to display the error then you will need to implement something else. Also, you can implement a lot more validations and other features with this library.

Hope this was helpful and, if you haven’t yet, try this wonderful library and even support them if you are able to.

Please like and share if you found this useful, until next time.

Top comments (8)

Collapse
lukeshiru profile image
Luke Shiru

The "vanilla" approach, without state or extra libraries:

import { FormEventHandler, useRef } from "react";
import "./styles.css";

const MAX_NAME_LENGTH = 12;
const MIN_NAME_LENGTH = 2;
const MAX_AGE = 99;
const MIN_AGE = 18;

const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
  event.preventDefault();

  // Instead of logging you'll send this to the back-end with fetch
  console.log(new FormData(event.currentTarget));
};

export default () => {
  const renderCount = useRef(0);

  return (
    <div className="App">
      <h1>React Native Form</h1>
      <p>Render count: {++renderCount.current}</p>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="name">name</label>
          <input
            id="name"
            type="text"
            maxLength={MAX_NAME_LENGTH}
            minLength={MIN_NAME_LENGTH}
            required
          />
        </div>
        <div>
          <label htmlFor="age">age</label>
          <input id="age" type="number" required max={MAX_AGE} min={MIN_AGE} />
        </div>
        <button>submit</button>
        <p>Check the console for output</p>
      </form>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Running on CodeSandbox:

The good thing about this approach is that you can even reuse that handleSubmit function in other libraries because FormData is a native API, so you can do the same thing in any library/framework out there.

You might say "but I want to customize the error messages", and that's a really bad idea given that if you use the native ones you get a11y for free. But if you really really want to customize them, you can still use checValidity and ValidityState and just show the errors based on that.

Cheers!

Collapse
ivanms1 profile image
Ivan Author

Thank you!
I forgot to add this example and I agree this is much more simple.
But like you said, this is perfect until you want anything custom, which might be a bad idea (?) but a lot of times it's a requirement we have follow.

Collapse
link2twenty profile image
Andrew Bone

I was about to write this response πŸ˜…

Collapse
romeerez profile image
Roman Kushyn

Would be nice to mention that react-hook-form supports integration with validation libraries, so we can define Zod schema (or to use other lib), type will be inferred, it can be reused between different forms, or even with server side if you have node.js backend, as the result it's even less code than with native approach and includes more validations, and no need to worry if some kind of validation doesn't work in Safari.

Collapse
ivanms1 profile image
Ivan Author

I'll try to add a section when I get the time.
I've only done it with yup, but I've heard some good things about zod, need to try it.

Collapse
bluebill1049 profile image
Bill

Awesome post! thank you for writing this and sharing. <3

Collapse
ivanms1 profile image
Ivan Author

Hey!
Thank you for all your work.

Collapse
darkwiiplayer profile image
π’Š©Wii πŸ’–πŸ’›πŸ’šπŸ’™πŸ’œπŸ’πŸ’Ÿ

Every now and then, I will come across one of these "how to X in framework Y" and it always amazes me how much complexity these frameworks end up adding to such simple scenarios.

It's just a form. It has state, as any vanilla form. It has events, like any vanilla form. There's nothing special going on here. Yet there's still so much code.

Head to your account's Settings to...

🌚 Enable dark mode
πŸ”  Change your default font
πŸ“š Adjust your experience level to see more relevant content