DEV Community

Cover image for The Ultimate Guide to Handling Forms in React
Marie Berezhna
Marie Berezhna

Posted on

The Ultimate Guide to Handling Forms in React

Introduction

Handling forms efficiently is a crucial part of building interactive applications. React provides multiple ways to manage form state, from simple controlled and uncontrolled components to powerful third-party libraries. In this guide, we’ll explore the key strategies for handling forms in React, comparing controlled vs. uncontrolled components, using libraries like Formik and React Hook Form, and implementing effective validation strategies.

1. Controlled vs. Uncontrolled Components

Controlled Components

Controlled components keep form state within the React component, making React the single source of truth.

Example of a Controlled Component

import { useState } from "react";

const ControlledForm = () => {
  const [name, setName] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`Submitted: ${name}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Enter your name"
      />
      <button type="submit">Submit</button>
    </form>
  );
};

export default ControlledForm;
Enter fullscreen mode Exit fullscreen mode

Pros of Controlled Components

  • Provides better control over form inputs
  • Easier to integrate with validation and state management
  • Ensures synchronization between UI and data

Cons

  • Can become inefficient in large forms due to frequent re-renders

Uncontrolled Components

Uncontrolled components store state within the DOM rather than React state.

Example of an Uncontrolled Component

import { useRef } from "react";

const UncontrolledForm = () => {
  const inputRef = useRef(null);

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`Submitted: ${inputRef.current.value}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" ref={inputRef} placeholder="Enter your name" />
      <button type="submit">Submit</button>
    </form>
  );
};

export default UncontrolledForm;
Enter fullscreen mode Exit fullscreen mode

Pros of Uncontrolled Components

  • Useful for integrating with non-React code
  • Avoids unnecessary re-renders

Cons

  • Less control over form state
  • Harder to implement validation and dynamic UI changes

2. Using Form Libraries (Formik & React Hook Form)

Formik

Formik simplifies form management by handling state, validation, and submission.

Example of a Formik Form

import { Formik, Form, Field } from "formik";

const FormikForm = () => {
  return (
    <Formik
      initialValues={{ email: "" }}
      onSubmit={(values) => alert(`Submitted: ${values.email}`)}
    >
      <Form>
        <Field type="email" name="email" placeholder="Enter your email" />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
};

export default FormikForm;
Enter fullscreen mode Exit fullscreen mode

Pros of Formik

  • Handles form state and validation easily
  • Great for complex forms #### Cons
  • More boilerplate code than React Hook Form

React Hook Form (RHF)

React Hook Form optimizes form handling by reducing re-renders.

Example of an RHF Form

import { useForm } from "react-hook-form";

const RHFForm = () => {
  const { register, handleSubmit } = useForm();

  const onSubmit = (data) => alert(`Submitted: ${data.email}`);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("email")} type="email" placeholder="Enter your email" />
      <button type="submit">Submit</button>
    </form>
  );
};

export default RHFForm;
Enter fullscreen mode Exit fullscreen mode

Pros of React Hook Form

  • Minimal re-renders, improving performance
  • Cleaner and more concise syntax

Cons

  • Requires understanding of React Hooks

3. Validation Strategies

Built-in Validation

HTML5 attributes can be used for basic validation.

<input type="email" required />
Enter fullscreen mode Exit fullscreen mode

Formik + Yup Validation

Formik integrates well with Yup for schema validation.

import * as Yup from "yup";
import { Formik, Form, Field, ErrorMessage } from "formik";

const validationSchema = Yup.object({
  email: Yup.string().email("Invalid email").required("Required"),
});

const FormikValidationForm = () => {
  return (
    <Formik
      initialValues={{ email: "" }}
      validationSchema={validationSchema}
      onSubmit={(values) => alert(`Submitted: ${values.email}`)}
    >
      <Form>
        <Field type="email" name="email" />
        <ErrorMessage name="email" component="div" />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
};

export default FormikValidationForm;
Enter fullscreen mode Exit fullscreen mode

React Hook Form + Yup Validation

import * as Yup from "yup";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

const schema = Yup.object({
  email: Yup.string().email("Invalid email").required("Required"),
});

const RHFValidationForm = () => {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: yupResolver(schema),
  });

  const onSubmit = (data) => alert(`Submitted: ${data.email}`);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("email")} type="email" />
      {errors.email && <p>{errors.email.message}</p>}
      <button type="submit">Submit</button>
    </form>
  );
};

export default RHFValidationForm;
Enter fullscreen mode Exit fullscreen mode

Conclusion

Managing forms in React can be streamlined using controlled/uncontrolled components, libraries like Formik and React Hook Form, and effective validation techniques. Choosing the right approach depends on your application's complexity and performance needs.

Which approach do you prefer? Let us know in the comments!

Top comments (0)