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;
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;
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;
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;
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 />
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;
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;
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)