Forms in React: Controlled vs. Uncontrolled Components

Introduction to Forms in React

Forms are essential for user input in web applications. In React, form handling can be done using two approaches:

  • Controlled Components: React handles the form data through state.
  • Uncontrolled Components: The DOM directly manages the form data.

Controlled Components

In controlled components, form inputs are bound to React state. This approach ensures React is the single source of truth for form data.

How It Works

  • Input values are set using value attributes tied to state.
  • Changes are handled using onChange events to update the state.

Example: Controlled Component

import React, { useState } from 'react';

function ControlledForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(`Name: ${name}, Email: ${email}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Name:
          <input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
        </label>
      </div>
      <div>
        <label>
          Email:
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

export default ControlledForm;

Uncontrolled Components

In uncontrolled components, form inputs are not bound to state. Instead, refs are used to access DOM elements directly.

How It Works

  • The ref attribute is used to reference input fields.
  • Values are retrieved using ref.current.value.

Example: Uncontrolled Component

import React, { useRef } from 'react';

function UncontrolledForm() {
  const nameRef = useRef();
  const emailRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(`Name: ${nameRef.current.value}, Email: ${emailRef.current.value}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Name:
          <input type="text" ref={nameRef} />
        </label>
      </div>
      <div>
        <label>
          Email:
          <input type="email" ref={emailRef} />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

export default UncontrolledForm;

Controlled vs. Uncontrolled Components

FeatureControlled ComponentsUncontrolled Components
Data HandlingManaged via React state.Managed directly by the DOM.
Access to DataData is always up-to-date in state.Use ref to access current values.
Use CasePreferred for dynamic, interactive forms.Simple forms or legacy code.
PerformanceCan be slower for large forms.Can be faster for simple forms.

Handling Form Submissions in React

Handling form submissions involves:

  1. Preventing the default form behavior using e.preventDefault().
  2. Accessing and validating the form data.
  3. Submitting the data (e.g., via an API).

Example: Form Submission

import React, { useState } from 'react';

function FormWithSubmission() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    const formData = { name, email };

    try {
      const response = await fetch('/api/submit', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(formData),
      });

      if (response.ok) {
        alert('Form submitted successfully!');
      } else {
        alert('Failed to submit form.');
      }
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Name:
          <input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
        </label>
      </div>
      <div>
        <label>
          Email:
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

export default FormWithSubmission;

Best Practices for React Forms

  1. Prefer Controlled Components: For consistency and better validation.
  2. Validate Inputs: Use libraries like Yup or Formik for form validation.
  3. Avoid Inline State Management: Use custom hooks for better code organization in large forms.
  4. Optimize Performance: Avoid unnecessary re-renders using React.memo or other optimization techniques.
  5. Use Libraries for Complex Forms: Libraries like Formik or React Hook Form simplify form handling.