Design Converter
Education
Last updated on Mar 29, 2025
•5 mins read
Last updated on Feb 19, 2025
•5 mins read
Struggling with form handling in React?
Forms can get tricky, especially when managing state, validation, and user interactions. Small mistakes can lead to frustrating bugs and slow performance.
The good news—React offers powerful tools to make form management easier. From controlled and uncontrolled components to libraries like React Hook Form, there are smart ways to handle form data without extra complexity.
This blog breaks down React forms best practices with the latest updates. You’ll learn how to manage form state, improve validation, and optimize performance.
Let’s get started!
React forms handle user input dynamically by connecting form elements with component state. There are two primary approaches:
Controlled Components: React manages the input value using state.
Uncontrolled Components: The browser controls the input elements, and React accesses values using refs.
Controlled components tie input values directly to the component’s state. Every change updates the state, which allows for real-time validation and dynamic behavior.
Example of a Controlled Component:
1import { useState } from "react"; 2 3function ControlledForm() { 4 const [formData, setFormData] = useState({ name: "", email: "" }); 5 6 const handleChange = (event) => { 7 setFormData({ 8 ...formData, 9 [event.target.name]: event.target.value 10 }); 11 }; 12 13 const handleSubmit = (event) => { 14 event.preventDefault(); 15 console.log("Form submitted with data:", formData); 16 }; 17 18 return ( 19 <form onSubmit={handleSubmit}> 20 <input 21 type="text" 22 name="name" 23 value={formData.name} 24 onChange={handleChange} 25 /> 26 <input 27 type="email" 28 name="email" 29 value={formData.email} 30 onChange={handleChange} 31 /> 32 <button type="submit">Submit</button> 33 </form> 34 ); 35} 36 37export default ControlledForm;
Uncontrolled components let the browser manage form state until submission, using refs to retrieve values.
Example of an Uncontrolled Component:
1import { useRef } from "react"; 2 3function UncontrolledForm() { 4 const nameRef = useRef(); 5 const emailRef = useRef(); 6 7 const handleSubmit = (event) => { 8 event.preventDefault(); 9 console.log("Form submitted with data:", { 10 name: nameRef.current.value, 11 email: emailRef.current.value 12 }); 13 }; 14 15 return ( 16 <form onSubmit={handleSubmit}> 17 <input type="text" name="name" ref={nameRef} /> 18 <input type="email" name="email" ref={emailRef} /> 19 <button type="submit">Submit</button> 20 </form> 21 ); 22} 23 24export default UncontrolledForm;
Both approaches have their use cases, though controlled components often provide finer control over form state and validation.
The latest version of React Hook Form has refined its API to minimize boilerplate while improving performance. Key features include:
• Minimal Re-renders: Thanks to its subscription-based state management, only the necessary components re-render.
• Built-in Validation: Leverage constraint-based validation using HTML standards, or integrate with schema validation libraries like Yup or Zod via resolvers.
• Enhanced TypeScript Support: Improved types make form handling more predictable and error-resistant.
Example using React Hook Form with schema validation via Yup:
1import { useForm } from "react-hook-form"; 2import { yupResolver } from '@hookform/resolvers/yup'; 3import * as Yup from 'yup'; 4 5const schema = Yup.object().shape({ 6 name: Yup.string().required("Name is required"), 7 email: Yup.string().email("Invalid email address").required("Email is required") 8}); 9 10function HookForm() { 11 const { 12 register, 13 handleSubmit, 14 formState: { errors } 15 } = useForm({ 16 resolver: yupResolver(schema) 17 }); 18 19 const onSubmit = (data) => { 20 console.log("Form submitted:", data); 21 }; 22 23 return ( 24 <form onSubmit={handleSubmit(onSubmit)}> 25 <input type="text" {...register("name")} /> 26 {errors.name && <span>{errors.name.message}</span>} 27 28 <input type="email" {...register("email")} /> 29 {errors.email && <span>{errors.email.message}</span>} 30 31 <button type="submit">Submit</button> 32 </form> 33 ); 34} 35 36export default HookForm;
Efficient form submission is critical for a smooth user experience. With React Hook Form, use the built-in handleSubmit function to manage validation and prevent default behavior without extra overhead:
• Prevent Default Behavior: Always call event.preventDefault() to avoid full page reloads.
• Leverage Resolvers: For schema-based validation, integrate with libraries like Yup to enforce consistent data formats.
• Graceful Error Handling: Use methods such as setError and clearErrors to provide immediate feedback to users.
When working with forms containing several inputs, React Hook Form lets you handle state updates efficiently:
• Single State Object: For manual state management (in controlled components), consolidate multiple fields into one state object.
• Subscription Model: With React Hook Form, each input subscribes only to its own state, minimizing unnecessary re-renders.
Validation is essential for preventing invalid data submission. Beyond manual validation, React Hook Form supports:
• Constraint-based Validation: Utilize HTML’s native validation attributes.
• Schema Validation via Resolvers: Easily integrate with Yup, Zod, or similar libraries to enforce complex rules.
Manual Validation Example:
1const validateEmail = (email) => /\S+@\S+\.\S+/.test(email); 2 3const handleSubmit = (event) => { 4 event.preventDefault(); 5 if (!validateEmail(email)) { 6 setErrorMessage("Invalid email format"); 7 } 8};
React Hook Form’s design minimizes performance overhead by:
• Isolating Component Re-renders: Only components watching specific fields update on changes.
• Using Hooks Like useWatch and useFormState: These hooks allow you to subscribe only to the form parts you care about.
• Controlled vs. Uncontrolled Approaches: Depending on your needs, choose the strategy that minimizes state changes.
For forms with numerous fields or dynamic inputs, advanced APIs from React Hook Form are invaluable:
• useFieldArray: Manage dynamic fields (e.g., arrays of inputs) without cumbersome state logic.
• Controller: Integrate controlled third-party UI components seamlessly.
• useReducer: For intricate state management, use React’s useReducer to centralize state updates.
Example Using Controller for Controlled Inputs:
1import { useForm, Controller } from "react-hook-form"; 2 3function ControlledInput() { 4 const { control, handleSubmit } = useForm(); 5 6 return ( 7 <form onSubmit={handleSubmit((data) => console.log(data))}> 8 <Controller 9 name="example" 10 control={control} 11 render={({ field }) => <input {...field} />} 12 /> 13 <button type="submit">Submit</button> 14 </form> 15 ); 16}
These techniques, along with hooks like useWatch and useFormState, ensure that even complex forms remain performant and manageable.
Mastering React forms best practices makes development smoother and more reliable. By using modern libraries like React Hook Form, you reduce code complexity while improving performance. Whether building simple forms or handling advanced validation, these strategies help create better user experiences. Keep refining your approach, stay updated with new techniques, and make your forms as user-friendly as possible.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.