close icon
daily.dev platform

Discover more from daily.dev

Personalized news feed, dev communities and search, much better than whatโ€™s out there. Maybe ;)

Start reading - Free forever
Start reading - Free forever
Continue reading >

Form on React: Best Practices

Form on React: Best Practices
Author
Nimrod Kramer
Related tags on daily.dev
toc
Table of contents
arrow-down

๐ŸŽฏ

Learn the best practices for handling forms in React, including using controlled components, real-time validation, and accessibility. Understand the differences between controlled and uncontrolled forms, and utilize libraries like Formik for complex forms.

Creating and managing forms in React doesn't have to be complicated. Here's a straightforward guide on best practices for handling forms effectively within your React applications:

  • Use Controlled Components: React state manages your form data, making it easier to handle changes and errors.
  • Perform Real-time Validation: Check user input as it's entered to catch errors early.
  • Display Errors Clearly: Show mistakes next to the relevant fields to help users correct them quickly.
  • Ensure Accessibility: Make your forms usable for everyone, including people with disabilities.
  • Submit Without Page Reloads: Use AJAX to send form data, improving user experience.
  • Consider Libraries for Complex Forms: Tools like Formik can simplify handling complicated forms.

These practices will help you build React forms that are efficient, user-friendly, and scalable. Whether you're dealing with controlled or uncontrolled components, understanding and implementing these strategies will enhance your form handling in React.

Controlled Components

With controlled components, React keeps an eye on the form data using its own state. This means React is in charge of the form data, not the webpage itself.

Here's the simple breakdown:

  • First, we set up the form's default values with something called the useState hook. Like this:
const [formData, setFormData] = useState({
  name: '',
  email: ''  
});
  • Next, we make sure the form inputs show the right state values. Like so:
<input 
  type="text"
  value={formData.name}
/>
  • When someone types in the form, we have a special function to update the state. Like this:
const handleChange = (e) => {
  setFormData({
    ...formData,
    [e.target.name]: e.target.value  
  });
}
  • When the form is sent, we use the state because it has all the form data.

Controlled components are great because they make checking the form and dealing with mistakes easier. Plus, they stop unexpected things from happening since the state always has the latest form data.

Uncontrolled Components

Uncontrolled components let the webpage (the DOM) handle the form data, not React. This means the state doesn't keep track of the form data.

Here's how it goes:

  • We use something called refs to connect directly to the form inputs. Like this:
const nameInputRef = useRef(null);
  • We attach these refs to the inputs. Like so:
<input 
  type="text"
  ref={nameInputRef} 
/>
  • When the form is sent, we use the refs to get the input values from the webpage. Like this:
const handleSubmit = () => {
  const enteredName = nameInputRef.current.value;
} 

Uncontrolled components skip the step of syncing the state with the input values. But, they make checking the form and dealing with mistakes a bit trickier since the webpage is the source of truth.

In short, both controlled and uncontrolled components have their places in React forms. Controlled components are better for forms that need checking and have complex stuff going on, while uncontrolled components are good when you want to keep things simple and not duplicate data in the state.

Prerequisites

Before you start making forms in React, here are some things you should know:

  • React Hooks and Components: You should be okay with using hooks like useState, useEffect, and useRef. Also, you should have tried making your own components before.
  • Handling State: You need to know how to use the useState hook for keeping track of your form's data and any errors. You should also know how to update the state when someone fills out the form.
  • Basic Form Stuff: You should understand the basics of how forms work, including inputs, labels, and how to show messages when something goes wrong.
  • Checking Forms: Knowing how to make sure everything filled out in the form is correct is important. This includes making sure all the required fields are filled, the format is right, and showing helpful error messages.
  • Sending Data: You'll need to know how to collect all the information from the form and send it somewhere, like to a server.

If you're comfortable with these things, you're ready to learn some best ways to build forms in React. We'll use examples that mainly talk about controlled forms with useState, but these ideas work for uncontrolled forms too.

Controlled vs. Uncontrolled Forms

In React, there are two main ways to handle forms: controlled and uncontrolled. Here's a quick comparison to understand them better:

Controlled Forms Uncontrolled Forms
Data Storage Stored in React state Stored in the DOM
Data Updating React state updates with form changes Directly access form data with refs
Checking Data Easier because React state is used Harder because you have to check the DOM
Performance Might slow down with lots of updates Faster because it doesn't update state
When to Use Best for forms that need checks Best for simple forms

Controlled Forms

Controlled forms keep all the form data in React's state. This means you can easily check and manage the data because React knows all about it.

How to set up a controlled form:

  • Start by using the useState hook to set up your state.
  • Make sure each form input shows the state's current value.
  • Create a function that updates the state whenever someone types in the form.

Here's a simple example:

function Form() {

  const [name, setName] = useState('');

  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <form>
      <input 
        value={name}
        onChange={handleChange} 
      />
    </form>
  )
}

Controlled forms are great for when you need to check user input closely. The downside? They might make your app run a bit slower because of the extra updates.

Uncontrolled Forms

Uncontrolled forms let the browser handle all the form data, not React. This means less work for React and potentially faster performance since it doesn't have to update the state every time something changes.

How to set up an uncontrolled form:

  • Use the useRef hook to create references for your form inputs.
  • Attach these refs to your inputs so you can grab their values easily.
  • When the form is submitted, use the refs to get the input values right from the form.

For example:

function Form(){

  const nameInputRef = useRef();

  const handleSubmit = () => {
    const enteredName = nameInputRef.current.value;
  }

  return (
    <form onSubmit={handleSubmit}>
      <input ref={nameInputRef} />

      <button>Submit</button>
    </form>
  )
}

Uncontrolled forms are simpler because they don't involve React state. But, this also means checking the data can be a bit trickier.

In short, use controlled forms when you need to keep a close eye on the data, and uncontrolled forms for simpler situations.

Best Practices for Controlled Forms

Controlled forms are super helpful but can be a bit tricky. Here are some tips to make your controlled forms in React work better and be more user-friendly.

Initialize All Values

When you start making your form with the useState hook, give every field a starting value. Don't just leave them empty. This way, you won't run into errors later on.

For example:

const [formData, setFormData] = useState({
  name: '',
  email: '',
  message: '' 
});

This helps avoid problems if you try to use values that aren't set yet.

Manage Async Data Carefully

Sometimes, you need to fill form fields with data from somewhere else, like a server. When you do this:

  • Show a loading sign so people know it's working.
  • If there's an error, make it clear what went wrong.
  • Use default values until the real data loads.

Smooth Out Controlled Inputs

Typing in controlled forms can feel slow because of how they update. To fix this:

  • Use debounce to slow down state updates and make typing feel smoother.
  • Boost performance by remembering calculations and using useCallback.
  • Try uncontrolled inputs if things get too complicated.

Validate Early and Clearly

With controlled forms, you can check if the data is right as soon as it's typed. Use this to:

  • Check fields as they're filled out.
  • Show clearly if something's wrong.
  • Tell people exactly what to fix.

Checking things step by step makes the whole process smoother.

Show Loading and Success States

When the form is sending, show that it's busy and stop people from changing anything. Once it's done, let them know everything went well and what to expect next.

These signs help people feel sure their form was sent properly.

Controlled Forms Take Practice

Controlled forms might take some time to get used to but they let you do a lot of cool stuff. Remember these tips:

  • Start off right by setting up your form properly.
  • Make typing feel good and not laggy.
  • Check the data as you go and be clear about errors.
  • Guide people through sending the form and what happens after.

Keeping these things in mind will help you make controlled forms that are easy and reliable.

Best Practices for Uncontrolled Forms

Uncontrolled forms are pretty handy when you want to keep things simple in your React app. They're great for forms that don't need a lot of checks and can help your app run faster. Here's how to get the most out of them:

Use When Forms Are Simple

Uncontrolled forms are best for straightforward forms. If your form just has a couple of fields and you don't need to worry about checking the info as people type, these forms can make your life easier.

Attach References with useRef

To work with uncontrolled forms, you'll use something called useRef. This lets you link directly to the form elements, like where someone types their name.

For example:

const nameInputRef = useRef();

return (
  <form>
    <input ref={nameInputRef} /> 
  </form>
)

Later, you can grab the input's value with nameInputRef.current.

Fetch Values on Submit

When it's time to send the form, just use the refs to get the input values.

For example:

const handleSubmit = () => {
  const enteredName = nameInputRef.current.value;
  
  // submit form
}

This way, you don't have to juggle the values in React's state, which keeps things simple.

Use Uncontrolled for Performance

If your form is slowing down because it's updating the state a lot, uncontrolled forms can help. They don't update the state every time something changes, so they can make your form faster.

Fallback to Controlled If Needed

Sometimes, you might need to add checks or other features to your form. If that happens, you might find it easier to switch to a controlled form, where you manage the state.

Uncontrolled Forms Take Practice

Uncontrolled forms can make things simpler in the right situations. Just remember:

  • They're good for simple forms.
  • Use useRef to connect to your inputs.
  • Get the values directly when submitting.
  • They can be faster because they don't update the state.
  • It's okay to switch to controlled forms if you need more features.

Keep these tips in mind, and you'll be able to use uncontrolled forms effectively in your React apps.

Form Validation

Checking if the form is filled out correctly is super important. This makes sure the info users give us is right and safe before we send it off. Here's how to do it well in React apps.

Validate on Change

It's best to check each part of the form right when it changes. This helps because:

  • It catches mistakes early before sending.
  • It clearly shows users what they need to fix.
  • It encourages fixing problems right away.

You can do this by making a function that checks the form and running it every time the form updates:

function validateForm(values) {
  // how to check the form
  return errors; 
}

function Form() {

  const [formValues, setFormValues] = useState();

  const [errors, setErrors] = useState({});

  function handleChange(e) {
    // update form values
    
    const validationErrors = validateForm(formValues);
    setErrors(validationErrors);
  }

}

Doing it this way makes it easier to fix mistakes compared to checking only when sending.

Validate All Fields

Make sure you check every part of the form, not just some. This includes:

  • Fields that must be filled
  • Text formats like emails
  • Numbers, like making sure they're not too low
  • Making sure passwords match

Checking everything helps make sure nothing wrong slips through.

Show Helpful Error Messages

Don't just say something is wrong. Tell users exactly what's wrong and how to fix it. For example:

  • "Email needs to have an @ symbol"
  • "Passwords need to be the same"
  • "Number needs to be more than 0"

Clear messages help users fix issues fast.

Use Built-in Validation

HTML forms have some checks built in that you can use, like:

  • making a field required
  • setting min or max lengths
  • setting number ranges
  • using patterns
  • setting custom rules

These checks happen in the browser before React even gets the info.

Consider Validation Libraries

For forms that have a lot going on, think about using a library like Formik or React Hook Form. They help with:

  • Ready-to-use check helpers
  • Managing form info
  • Handling error messages
  • Fitting in smoothly with React

Libraries offer strong checking features that work well with React.

In short, checking forms is key for making sure they're filled out right and safe. Do it often, check everything, be clear about what's wrong, use what's already available, and think about using libraries for big forms. Good checking makes forms better for everyone.

Error Handling in Forms

Making sure users know when they've made a mistake on a form is key to a good experience. You want to point out the errors clearly and help them fix them easily. Here are some smart ways to handle errors in React forms:

1. Show Error Messages Right Next to the Field

Put any error messages right by the field where the mistake was made. This makes it easy for users to see what they need to fix:

<Form>
  <label>Email</label>
  
  <input 
    type="email"
  />
  
  {errors.email && <p>Please enter a valid email</p>}
  
</Form>

This way, users don't have to look around to find out what went wrong.

2. Use Clear, Helpful Messages

Make sure your messages tell users:

  • What the mistake is
  • How to fix it

For example:

โŒ "Email invalid" โœ… "The email address should contain an '@' symbol"

Clear instructions help users fix errors fast.

3. Allow Immediate Corrections

Don't stop users from editing a field if they make a mistake. Let them fix it right away.

4. Focus on the Big Errors First

If there are several mistakes, show the most important ones first, like missing required fields, before worrying about smaller issues.

5. Use Conditional Rendering

Only show error messages if there are actually errors to talk about. This keeps things simple and not too crowded:

{errors.length > 0 && 
  <div>
    {errors.map(error => (
      <p key={error}>{error}</p>
    ))}
  </div>
}

The main idea is to make error messages easy to understand and helpful, guiding users to quickly correct any issues. Getting error handling right in React forms means smoother, more user-friendly experiences.

sbb-itb-bfaad5b

Utilizing Form Libraries

Using libraries like React Hook Form, Formik, and Redux Form can make your life a lot easier when you're creating forms in React that are a bit more complicated. Here's why they're helpful:

Easier to Keep Track of Things

These libraries take care of the hard parts of keeping track of what's being typed into forms, checking for mistakes, and so on. This means you don't have to write as much code to manage the form's state, making your job easier.

They Help with Checking for Mistakes

They come with tools that help you check for common errors, like making sure a field isn't left blank, that an email address looks right, or that passwords match. This saves you from having to write all this checking yourself.

Good for Forms that Change Based on What's Happening

If you need to create forms that change based on what a user does (like adding more questions if they answer a certain way), these libraries have features that make this easy, like adding or removing fields dynamically.

Making Mistakes Clear

They also make it simpler to show error messages right where the mistakes are, helping users fix them. The libraries handle the errors, so you focus on making the form look good.

Checking Fields Against Each Other

Sometimes, you need to make sure two fields agree with each other, like confirming a password. Form libraries have easy ways to do this kind of check without adding a lot of extra work.

Made for React

These libraries are built to work well with React, meaning they fit right into how you build components. They're smart about only updating parts of your form when needed, which helps keep your app running smoothly.

In short, using a form library can save you a lot of time and trouble when you're building more complex forms in React. They handle a lot of the routine work for you, letting you focus on the parts of your form that users see and interact with. For bigger projects, they're definitely worth considering.

Integrating Third-party Libraries

When you're working on more complicated forms in React, using some extra tools can really help. These tools, or libraries, do a lot of the heavy lifting, so you can focus on making your forms nice and user-friendly.

In this part, we'll talk about two useful tools:

  • React Query for grabbing data
  • Zod for making sure the data is correct

These tools help you manage data and make sure it's right, which makes your forms work better.

Getting Set Up with React Query

React Query is a tool for React that helps with getting data from the server, keeping it up to date, and more.

To add React Query to your project:

npm install react-query

Then, you need to wrap your app with QueryClientProvider:

import { QueryClient, QueryClientProvider } from 'react-query'

const queryClient = new QueryClient()

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <MyForms /> 
    </QueryClientProvider>
  )
}

Now, you can start using React Query to get data for your forms.

Fetching Form Options with React Query

Often, forms need data from somewhere else, like a list of options for a dropdown. Here's how you can get that data:

import { useQuery } from 'react-query'

function CategoriesSelect() {

  const { data, isLoading } = useQuery('categories', fetchCategories)  

  if (isLoading) return <span>Loading...</span> 

  return (
    <select>
      {data.map(category => (
        <option key={category.id}>{category.name}</option>
      ))}
    </select>
  )
}

React Query takes care of getting the data, updating it, and more, which makes your form components reliable.

Integrating Zod for Validation

Zod is a tool for checking if the data in your forms is right. You set up rules for your data, and Zod helps you spot any mistakes.

To start using Zod:

npm install zod 

Then, you make a set of rules for your form data:

import { z } from 'zod'

const formSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
})

And use these rules to check your data:

formSchema.parse(formData) // catches errors

Zod can check things like types, required fields, and more. It works well with React, especially for showing errors right in your forms.

By using React Query and Zod together, you can make forms that handle data and check it properly. Try them out in your next React project!

Creating Reusable Form Components

Making form components that you can use again and again is a smart move when building forms in React. This means you create custom inputs, hooks, and bits and pieces once and then use them in many places. This approach helps keep your forms looking and acting the same, cuts down on repeating the same code, and makes building things faster.

Benefits of Reusable Form Components

Here's why reusable form components are a good idea:

  • Consistency - Using the same components everywhere means your forms will look and work the same way, making things predictable for users.
  • Less Code - You won't have to write the same stuff over and over because your components take care of the tricky parts. This speeds up how quickly you can make things.
  • Easier Maintenance - If something needs updating, like how a form checks for errors, you just do it in one spot.
  • Flexible - Good components can be tweaked with props to fit different needs, making them super versatile.

In the long run, reusing components makes your forms better and your code cleaner.

Creating a Custom useForm Hook

A cool trick is to make a custom hook called useForm that handles common form tasks. Here's a simple version:

import { useState } from 'react';

function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);

  function handleChange(e) {
    // update values
  }

  function resetForm() {
    // reset values
  }

  return {
    values,
    handleChange,
    resetForm
  };
}

export default useForm;

And here's how you might use it in a form:

function MyForm() {
  
  const { 
    values, 
    handleChange,
    resetForm
  } = useForm({
    name: ''
  });

  return (
    <form>
      <input 
        value={values.name}
        onChange={handleChange}  
      />
    </form>
  )
}

This hook helps clean up your components by keeping the state management stuff out of the way.

Tips for Reusable Components

Here are some pointers:

  • Be open to props for more options
  • Use custom hooks to manage state
  • Make sure they can stand on their own
  • Test them to avoid surprises
  • Write down how to use them so others can easily pick them up

Taking the time to build reusable parts makes handling forms in React much smoother as your project grows.

Handling Multiple Input Fields

When you're dealing with a lot of input fields in a React form, it might seem a bit complex at first. But, with a few smart moves, it can be pretty straightforward. Here's how to manage multiple inputs smoothly:

1. Use a Single State Object

Instead of having a separate state for each input, it's easier to keep everything in one big state object. This way, all your form data is in one spot:

const [formData, setFormData] = useState({
  firstName: '',
  lastName: '',
  email: ''  
});

This method keeps things tidy and simple.

2. Add a name Attribute to Inputs

Make sure each input field has a name that matches its key in the state object:

<input 
  name="firstName"
  value={formData.firstName}
/>

This tells React which part of the state to update when things change.

3. Handle Changes with a Single Function

You can use just one function to handle changes for all the fields. It looks at the input's name to know which part of the state to update:

function handleChange(e) {
  setFormData({
    ...formData,
    [e.target.name]: e.target.value
  });  
}

This way, you don't need a bunch of separate functions for each input.

4. Validate on Submit

When the form is sent, you can check all the fields at once by looking through the state object:

function handleSubmit() {
  let errors = {};

  // validate each field

  setErrors(errors);
}  

Using this method makes handling lots of inputs much easier and keeps your form flexible. If you have more questions, feel free to ask!

Submitting Forms

When you're ready to send your form in React, you want everything to go smoothly for the people using your app. Here's how to make sure both controlled and uncontrolled forms are sent off correctly:

Controlled Form Submission

In controlled forms, you keep the form data in React's state. Here's what to do when sending the form:

  • Use an onSubmit handler on the <form> tag. This function kicks in when the form is submitted.
  • Stop the form from sending the usual way with event.preventDefault() inside your submit handler. This prevents the page from refreshing.
  • Gather the form data from React's state and send it over to the server. Like this:
function handleSubmit(event) {
  event.preventDefault();
  
  // send formData state to API
  submitToApi(formData); 
}

return (
  <form onSubmit={handleSubmit}>
    ...
  </form>
)
  • After sending, you can change the state to show a message that everything went well, clear out the form, or take the user somewhere else.

Uncontrolled Form Submission

In uncontrolled forms, the form data is in the DOM, not in React's state. To send the form:

  • Put a submit handler on the <form> tag.
  • Inside the handler, use event.preventDefault() to stop the form from sending the usual way.
  • Use refs to grab the form data straight from the DOM inputs.

Like this:

function handleSubmit(event) {
  event.preventDefault();

  const name = nameRef.current.value;
  
  // submit form data
}

return (
  <form onSubmit={handleSubmit}>
    <input ref={nameRef} />
  </form>
) 
  • After sending, update the screen to show a message that everything went well.

General Tips

  • Show a spinner or disable the submit button while the form is sending.
  • If everything goes well, pop up a friendly message to let the user know.
  • If there's a problem, make sure to explain it clearly and let the user try again.
  • Once the form is sent, you can clear the data, reset everything, close a pop-up, or move the user to a new page.

Making sure your form sends off properly can really make a difference in how people see your app. Follow these steps for a smooth, hassle-free experience in your React apps.

Conclusion

Handling forms is a key part of making web apps that are easy to use. By sticking to good practices for managing forms, checking them, and dealing with mistakes, you can make forms in React that work well and feel smooth to use.

Here's what to remember:

  • Choose controlled forms when you need tight control over the form's data, want to check inputs right away, and handle errors smoothly. Uncontrolled forms are simpler but can make checking inputs harder.
  • Check your forms often as people fill them out, look at every field, and give clear messages about what to fix. You might want to use tools like React Hook Form for complicated forms.
  • Make sure error messages are easy to see and fix right next to the problem areas. Deal with the big issues first before the small ones.
  • Make typing in controlled forms feel better by using tricks like debouncing, remembering calculations, and sometimes using uncontrolled inputs instead.
  • Set up all form fields from the start to avoid surprises later.
  • Help users through the form with signs that it's working, success messages, and guiding them on what to do after submitting.
  • Build inputs, hooks, and parts you can use over and over to cut down on repeating yourself. Custom hooks like useForm can help with managing data.
  • Use tools like React Query and Zod for getting data and making sure it's correct.

Thinking ahead about how to set up your forms, making parts you can use many times, and using the right tools can make your code easier to handle and make your users happy. Keep these tips in mind when you're working on forms in your React projects.

What is the best way to handle forms in React?

HERE'S A TIP:

  • Break your form into smaller parts.
  • Avoid using react-hook-form just for state management.
  • Organize your form based on the order of steps needed.
  • Treat each step as its own react-hook-form setup.

What is the best practice for form validation in React?

Best Practices for Form Validation:

  • Always check the data on the server-side too, to catch any wrong or harmful data.
  • Think about using libraries like Formik or React Hook Form. They make managing and checking your form's data easier.

What is the best form module for React?

Formik is a widely used and feature-rich library for handling forms in React and React Native. It takes care of managing the form's state, checks the data, and handles sending the form for you.

What are the best practices for React?

Some key tips for working with React:

  • Keep your files organized in a clear way
  • Be consistent with how you order imports
  • Stick to naming conventions
  • Use tools like ESLint to help with code quality
  • Make use of code snippets
  • Use styled components to mix CSS with JavaScript
  • Try not to make too many components
  • Use lazy loading to improve how fast your app loads

Related posts

Why not level up your reading with

Stay up-to-date with the latest developer news every time you open a new tab.

Read more