React Hook Form is about turning 2 years old. The project itself is still as active as it was on day one. Over the years, there have been lots of learnings and experiences which contributed to the make and design of Version 7. I am here to present you with some of the reasons and improvements in the next major version. Our mission remains the same is to make every React developer's life easier in terms of building forms.
V7 visions:
π (DX) Strictly typed form
πββοΈ Simplicity and consistency
π Performance
ππ»ββοΈ Reduce package size
Let's diving into the APIs to reflect those visions which we have set from the beginning.
</> register
One of the major changes will be the register
API. As most of you would know React Hook Form is built on typescript
, and having type-safe is an important aspect for most typescript
developers. One of the challenges that we are facing is to type check input name
. This is made possible with typescript 4.1 update Template Literal. I was really excited to find that out and started planning ahead to make sure this new feature will be compatible with React Hook Form.
Here is the necessary change:
- <input name="test" ref={register} />
+ <input {...register('test')} />
// the following props will be spread into inputs
const { onChange, onBlur, ref, name } = register('test');
As you can see above, now we can do a type check by invoking the function above. The original API has its pros and cons, and it's definitely not compatible with type-safe. Adopting this change will affect the type check to the rest of the hook form's API, such as useController
, Controller
and etc.
The following image demonstrates the type check against the nested field input name.
You can try out with the following codesandbox with beta
version installed:
</> resolver
For those who are using schema validation, resolver
is getting power lifted. The current resolver lacks validation context, which means the formation about the inputs been validated are missing. We are improving on this part, developers will be able to access which field is been validated and so do its ref
. This can potentially unlock the following functionality:
Validation optimization: If any schema validation library support field-level validation, this will allow the developer to optimize validation without running the entire schema each
onChange
.Focus management: Access to the input DOM element for better custom focus management.
Here is the Resolver's type definition:
- resolver: (values: any, context?: object) => Promise<ResolverResult> | ResolverResult
+ resolver: (
+ values: any,
+ context: object | undefined,
+ options: {
+ criteriaMode?: 'firstError' | 'all',
+ names?: string[],
+ fields: { [name]: field } // Support nested field
+ }
+ ) => Promise<ResolverResult> | ResolverResult
Joris is the man behind all those amazing work, he will write a detailed technical blog post around resolver
.
</> useFormState
As the current version of hook form, form state update will be re-rendered at the root/form level where you invoked useForm
. This is about to change in Version 7, with this newly introduced custom hook useFormState
, you can subscribe to individual form state update at the component level. This means as a developer you have control over when your components get informed with form state update. We have also baked useFormState
into useController
and Controler
, so each controlled input will be completely isolated in terms of re-render.
// Subscribe to isDirty, touchedFields at the component level
const { isDirty, touchedFields } = useFormState();
// Subscribe **only** to isDirty and isTouched.
const Test = () => {
const { meta: { isDirty, isTouched } } = useController();
}
Here is a good example of our DevTool
in which the re-render is isolated at the component level by leveraging this new custom hook.
</> useForm
From the beginning of the initial version, we are trying to be aligned with HTML standards and how native form behaviors. One of the examples is when input removed, its value will be omitted too. However, such behavior also made many React developers confused about why input value disappeared after unmount, to ease the concern we had to introduce shouldUnregister
config to give users the option. As a result, this leads to quite a lot of extra logic and complexity within the codebase. In Version 7, we are dropping shouldUnregister
, which means developers will have to control their input value remove with unregister
. It definitely has its own pros and cons, but I think this change will make more sense to most React developers. Here is an example below:
const [show, setShow] = React.useState(true);
// V6 the following input value will be removed
{show && <input ref={register} name="test"}
// V7 the following input value will be retained
{show && <input {...register('test')}} // V7
// V7 until the following line is invoked then the value will be removed
unregister('test')
The change also helped a lot with the lib bundle size.
Conclusion
React Hook Form will have better type checks in general, smaller, faster, and more developer-friendly. I hope the post will explain what are the rationales and improvements that we are trying to bake into Version 7. If you have any feedback, concern, or question, you can always join our Version 7 RFC:
You can also watch this short talk which I posted on youtube around V7 (17mins).
Bonus
We also made the following improvement:
Documentation:
Thanks
Thanks go to everyone who is involved and contributed to this major version. Special thanks go to:
Joris who has made the next version of the
resolver
and the rest of hook form team.wdfinch who has consistently involved in V7 discussion and reporting bugs and issues alone the way.
β€οΈ Thank you for backing and sponsoring the project!
Top comments (6)
Thanks for the very clear summary, really appreciate it!
react-hook-form is a very good library, bravo!
Thank you Vincent for your support and for always post solutions to help many others.
Thanks for the updates.
Documentation looks better
Thank you.
Nice one Bill! Love your work ππ
Thanks, Lucas. Awesome to hear.