Performance of React Hook Form
Performance is one of the primary goals for building this custom hook. React Hook Form relies on uncontrolled component, hence the reason why the register function occurs at the ref. This approach will reduce the amount of re-rendering occurring due to user typing or value changing. Components mount to the page is much quicker as well because they are not controlled. For mounting speed, I have completed a quick comparison test which you can refer to by this repo link.
How to create an accessible input error and message?
React Hook Form is based on Uncontrolled Component, which gives you the ability to build an accessible custom form easily.
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="text"
aria-invalid={errors.firstName ? "true" : "false"}
aria-describedby="firstNameError"
name="firstName"
ref={register({ required: true })}
/>
<span id="firstNameError" style={{ display: errors.firstName ? "block" : "none" }}>
This field is required
</span>
<input type="submit" />
</form>
);
}
Does it work with Class Components?
No, not out of box. but you can build a wrapper around it and use in your Class Component.
You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
How to reset the form?
There are two methods to clear the form.
- HTMLFormElement.reset()
This method does the same thing as clicking a form's reset button, and only clears
input/select/checkbox
values. - React Hook Form API:
reset()
React Hook Form's
reset
method will reset all fields value, and also will clear allerrors
within the form.
How to initialize form values?
React Hook Form relies on uncontrolled component. With an uncontrolled component, you can specify a defaultValue
or defaultChecked
to an individual field. However, the hook itself does provide an easier way to initialise all input values too. Example below:
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit } = useForm({
defaultValues: {
firstName: "bill",
lastName: "luo",
email: "bluebill1049@hotmail.com"
}
});
const onSubmit = data => alert(JSON.stringify(data));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="firstName" ref={register} />
<input name="lastName" ref={register} />
<input name="email" ref={register} />
<button type="submit">Submit</button>
</form>
);
}
How to share ref usage?
React Hook Form needs ref
to collect the input value, however, you may want to use ref
for other purposes (eg. scroll into the view). The following example will show you how.
import React, { useRef } from "react"
import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit } = useForm()
const firstNameRef = useRef()
const onSubmit = data => alert(JSON.stringify(data))
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="firstName" ref={(e) => {
register(e)
firstNameRef.current = e // you can still assign to ref
}} />
<input name="lastName" ref={(e) => {
// register's first argument is ref, and second is validation rules
register(e, { required: true })
}} />
<button>Submit</button>
</form>
);
}
What if you don't have access to ref?
You can actually register
an input without a ref
. In fact, you can manually setValue
, setError
and triggerValidation
.
Note: Because ref
has not been registered, React Hook Form won't be able to register event listeners to the inputs. This means you will have to manually update value and error.
import React, { useEffect } from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit, setValue, setError } = useForm();
const onSubmit = data => alert(JSON.stringify(data));
useEffect(() => {
register({ name: "firstName" }, { required: true });
register({ name: "lastName" });
}, [])
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
name="firstName"
onChange={e => setValue("firstName", e.target.value)}
/>
<input
name="lastName"
onChange={e => {
const value = e.target.value;
if (value === "test") {
setError("lastName", "notMatch")
} else {
setValue("lastName", e.target.value)
}
}}
/>
<button>Submit</button>
</form>
);
}
Browser Support?
React Hook Form support all major browsers.
For legacy IE11 support, you can import react-hook-form IE 11 version.
import { useForm } from 'react-hook-form/dist/react-hook-form.ie11'
If you encounter:
Object doesn't support property or method 'find'
You should try to add this find polyfill to the top of your app.js
Why is first keystroke is not working?
Double check if you are using value
instead of defaultValue
.
React Hook Form is built based on uncontrolled input, which means you don't need to change input value
via state
by onChange
. Hence you don't need value
at all, in fact, you only need defaultValue
for initial input value.
Testing failed due to MutationObserver?
If you have difficulty during testing and the issue was caused by MutationObserver
. Make sure you install mutationobserver
and import this package in your test setup.js file.
React Hook Form, Formik or Redux Form?
First of all, all libs try to solve the same problem which is making form building experience easy and great. However, there are some fundamental differences between the three, react-hook-form is built with uncontrolled input in mind and tries to provide your form with best performance and least re-render if possible. On top of that, react-hook-form is built by React Hook and used as hook, which means there is no Component for you to import. Here are some of the detail differences:
React Hook Form | Formik | Redux Form | |
---|---|---|---|
Component | uncontrolled & controlled | controlled | controlled |
Rendering | minimum re-render | re-render according to local state changes which means as you type in the input. | re-render according to state management lib (Redux) changes which means as you type in the input. |
API | Hooks | Component (RenderProps, Form, Field) + Hooks | Component (RenderProps, Form, Field) |
Package size | Smallreact-hook-form@4.0.0 | Mediumformik@2.0.1 | Largeredux-form@8.2.6 |
Validation | Built-in & Yup | Build yourself or Yup | Build your yourself or Plugins |
Learning curve | Low | Medium | Medium |
Status | Medium Community: New lib and growing | Large Community: Well established form lib in the community | Large Community: Well established form lib in the community |
Can it work with Controlled component?
Short answer: Yes
React-hook-form is not recommending you to build form controlled, however you can still achieve that easily.
The trick to using watch
API to monitor each input's change and assign to value prop.
Alternatively, you can use our wrapper component Controller which take care those custom register for you.
import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField } from "@material-ui/core";
function App() {
const { control, handleSubmit } = useForm();
const onSubmit = data => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
as={<TextField />}
name="firstName"
control={control}
defaultValue=""
/>
<input type="submit" />
</form>
);
}
Testing React Hook Form
Why am I getting
act
warning?All validation methods in React Hook Form will be treated as async functions, so it's important to wrap
async
around your act.Why input change is not fire event?
React Hook Form using
input
event for input change, so to fix it. you can easily switch tofireEvent.input
for react-testing-library
watch vs getValues vs state
watch: subscribe to input’s change via event listener and re-render based on which fields that are subscribed. Check out this codesandbox for actual behaviour.
getValues: get value which stored inside the custom hook as reference, fast and cheap. This method doesn’t trigger re-render.
local state: React local state represent more than just input’s state and also decide what to render. This will trigger on each input’s change.
We Need Your Support
If you find React Hook Form to be useful in your React project, please star to support the repo and contributors ❤