Swizec Teller - a geek with a hatswizec.com

    Why react-hook-form is my new favorite form library

    Forms are fun. They start simple then blow up in your face.

    You've seen this pattern in every React tutorial with form fields:

    Click through for source
    Click through for source

    Click through for source
    Click through for source

    A controlled input. Gets value from state, updates value on change. Works great πŸ‘

    Keeping form values in state is convenient for business logic. You trigger a re-render for every keypress but that's okay, React is fast.

    Then you add more fields ...

    Click through for source
    Click through for source

    Click through for source
    Click through for source

    That sure blew up πŸ˜…

    State up the wazoo, re-renders on any field change, and you haven't even thought about validation, error states, dirty states, and all the rest that goes into a form.

    You're smart and you can make this work. I know you can {{ subscriber.first_name | truncatewords: 1, "" | capitalize }}.

    But imagine a monster form like I was dealing with last week.

    Click through for source
    Click through for source

    πŸ˜‡

    Custom form generators help

    You can build a form generator to remove the repetitive work.

    Helper component, a loop or two, and off you go, right?

    Click through for source
    Click through for source

    Click through for source
    Click through for source

    Ok I didn't use loops, but you get the idea.

    The <Input> component is generic and we pass-in state and setters from above. Then you can add errors, default values, different styles, etc.

    You don't want to push state handling into the Input component itself. That's a recipe for pain.

    A better approach might be to turn form state into an object and build a reducer.

    Click through for source
    Click through for source

    Click through for source
    Click through for source

    Your form state lives inside an object – one key per field. You can always see current state and you always know what's going on.

    For easy updates you've got the valueSetter method that returns a function to update a single field.

    Works great πŸ‘

    You're triggering a full re-render for every field change, you don't have validations, no way to show errors, and no way to know when a field is dirty.

    PS: dirty fields are fields that changed and the value hasn't been saved yet

    loser giphy

    react-hook-form makes everything better

    react-hook-form solves those problems for you.

    It's a hook-based form solution that takes care of:

    • managing state
    • errors
    • dirty fields
    • validations

    And minimizes re-renders by avoiding controlled inputs.

    Yep, react-hook-form uses the fields themselves to keep state. Pulls it out when you need it.

    Here's the example above built with react-hook-form:

    Click through for source
    Click through for source

    State management turns into this:

    Click through for source
    Click through for source

    Setting up a field turns into this:

    Click through for source
    Click through for source

    The register method returns a React ref and sets up the form machinery.

    And when you're ready to submit, values come as an object with a key for every field.

    love giphy

    You get HTML5 validations out of the box. They show up in the errors object. Like this:

    Click through for source
    Click through for source

    Click through for source
    Click through for source

    By default validations run on change.

    And you can change that with a line of code 😍

    Click through for source
    Click through for source

    Add context for more flexibility

    Passing errors and registers into every field like above is silly. Too much work.

    That's why react-hook-form supports context.

    Using the same approach as my Wormhole state management article:

    • create a form
    • put everything in context
    • wormhole to context with a hook

    You get form components that magically connect to your form. Register themselves, know about errors, dirty states. Everything 😍

    Like this

    Click through for source
    Click through for source

    Click through for source
    Click through for source

    Every field validates a 2 character minLength and displays its own errors.

    Using them in a form looks easy now:

    Click through for source
    Click through for source

    excited giphy

    Add Yup for big validations

    You've got the machinery to spit out forms now. Small schlep and you're done.

    Render a form, pepper it with <Input name="X" /> fields and voila. Happy boss, happy customer, happy you.

    And then it's time for real validations. Not minLength or required. Real validations. The kind where lastName is required, but only if firstName is filled in.

    gulp giphy

    You can add yup for that. react-hook-form supports it out of the box ✌️

    Here's the example above that validates you wrote the whole address, but only if you wrote the street name.

    Click through for source
    Click through for source

    To make that happen you πŸ‘‡

    Write a Yup schema describing the shape of your data. Bit of an art to it, make sure you don't fall off the deep end with conditional validations. They get tricky.

    Click through for source
    Click through for source

    The Yup docs are okay, not stellar. I recommend tinkering until it works.

    Then you tell react-hook-form about your schema:

    Click through for source
    Click through for source

    And change your register call back to vanilla:

    Click through for source
    Click through for source

    And you've got reusable field components that work with any form. Pop them in, set the schema, get validations and error handling and all the rest.

    peace giphy

    Happy hacking

    Cheers,
    ~Swizec

    PS: in my code I went as far as a generic <Form> component that sets up the context provider and <form> element for me.

    Did you enjoy this article?

    Published on August 3rd, 2020 in Front End, Technical

    Learned something new?
    Want to become an expert?

    Here's how it works πŸ‘‡

    Leave your email and I'll send you thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

    Join Swizec's Newsletter

    And get thoughtful letters πŸ’Œ on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.

    "Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. πŸ‘Œ"

    ~ Ashish Kumar

    Join over 14,000 engineers just like you already improving their careers with my letters, workshops, courses, and talks. ✌️

    Have a burning question that you think I can answer?Β I don't have all of the answers, but I have some! Hit me up on twitter or book a 30min ama for in-depth help.

    Ready to Stop copy pasting D3 examples and create data visualizations of your own? Β Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization

    Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.

    Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first πŸ’° on the side with ServerlessReact.Dev

    Want to brush up on your modern JavaScript syntax?Β Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❀️

    Created bySwizecwith ❀️