Controlled and Uncontrolled Components in React

In React, forms can be created using either controlled or uncontrolled components. Understanding the difference between the two is essential for managing form state and user inputs effectively.

Controlled components

Which components are controlled by the React and state handle all the form data is known as controlled components

Uncontrolled components

Which components are controlled and managed by DOM is known as uncontrolled components

Controlled Components

Controlled components are those where the form data is handled by the React component's state. The state becomes the "single source of truth" for the input elements.

Example of a Controlled Component

import React, { useState } from 'react';

const ControlledForm = () => {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (event) => {
    setInputValue(event.target.value);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`Input value: ${inputValue}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Input:
        <input type="text" value={inputValue} onChange={handleChange} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
};

export default ControlledForm;
Note

In controlled components, the input's value is always driven by the React state, making it easy to enforce validation and manipulate the input programmatically.

Uncontrolled Components

Uncontrolled components rely on the DOM to handle form data. Instead of using state, refs are used to access the input's value directly from the DOM.

Example of an Uncontrolled Component

import React, { useRef } from 'react';

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

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

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Input:
        <input type="text" ref={inputRef} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
};

export default UncontrolledForm;
Warning

Uncontrolled components can be simpler to implement, but they provide less control over the form data and can be harder to debug.

When to Use Controlled vs Uncontrolled Components

Controlled Components

  • Use cases: When you need to validate input, conditionally enable/disable form elements, enforce input formats, or integrate with other state-driven logic.
  • Benefits: Easier to manage form state, validate inputs, and enforce rules.
  • Drawbacks: More boilerplate code and potentially more re-renders.

Uncontrolled Components

  • Use cases: When you need a quick form with minimal logic, such as a simple subscription form.
  • Benefits: Less code and potentially better performance due to fewer re-renders.
  • Drawbacks: Harder to validate inputs and manage form state.
Deep Dive

Consider using controlled components when building complex forms where validation and interactivity are crucial. Use uncontrolled components for simpler forms where quick and easy implementation is needed.

Hybrid Approach

Sometimes, a hybrid approach can be used, combining both controlled and uncontrolled components to balance performance and control.

Example of a Hybrid Approach

import React, { useState, useRef } from 'react';

const HybridForm = () => {
  const [formData, setFormData] = useState({ email: '' });
  const inputRef = useRef(null);

  const handleChange = (event) => {
    setFormData({ ...formData, [event.target.name]: event.target.value });
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(`Email: ${formData.email}, Name: ${inputRef.current.value}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Email:
        <input
          type="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Name:
        <input type="text" ref={inputRef} />
      </label>
      <br />
      <button type="submit">Submit</button>
    </form>
  );
};

export default HybridForm;
Under Construction

The hybrid approach can be useful when you need to control certain inputs but want to keep others simple and unmanaged.

Conclusion

Both controlled and uncontrolled components have their use cases and benefits. Controlled components offer more control and are ideal for complex forms, while uncontrolled components are simpler and can be useful for quick, straightforward forms.

Task

Creating Controlled and Uncontrolled Components

Objective: Create a controlled and an uncontrolled form component to understand the differences in implementation and use cases.

  1. Create a Controlled Form Component:

    Create a new file ControlledForm.jsx and define a controlled form component with validation.

    import React, { useState } from 'react';
    
    const ControlledForm = () => {
      const [inputValue, setInputValue] = useState('');
    
      const handleChange = (event) => {
        setInputValue(event.target.value);
      };
    
      const handleSubmit = (event) => {
        event.preventDefault();
        if (inputValue.trim() === '') {
          alert('Input cannot be empty');
        } else {
          alert(`Input value: ${inputValue}`);
        }
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <label>
            Input:
            <input type="text" value={inputValue} onChange={handleChange} />
          </label>
          <button type="submit">Submit</button>
        </form>
      );
    };
    
    export default ControlledForm;
    
  2. Create an Uncontrolled Form Component:

    Create a new file UncontrolledForm.jsx and define an uncontrolled form component.

    import React, { useRef } from 'react';
    
    const UncontrolledForm = () => {
      const inputRef = useRef(null);
    
      const handleSubmit = (event) => {
        event.preventDefault();
        if (inputRef.current.value.trim() === '') {
          alert('Input cannot be empty');
        } else {
          alert(`Input value: ${inputRef.current.value}`);
        }
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <label>
            Input:
            <input type="text" ref={inputRef} />
          </label>
          <button type="submit">Submit</button>
        </form>
      );
    };
    
    export default UncontrolledForm;
    

By completing this task, you'll gain practical experience in implementing and using both controlled and uncontrolled components in React.