Q: What is the difference between Controlled and Uncontrolled Components in React?

Answer:

This question fundamentally asks about how forms and input data are handled within a React application. The difference lies in who controls the current state of the data: React, or the DOM itself.

1. Controlled Components (React handles the state)

In a controlled component, the form data is handled strictly by the React component. React acts as the "Single Source of Truth."

You track the input's value using useState and update it dynamically using an onChange handler. The input element only displays what the React state tells it to display.

import { useState } from 'react';

function ControlledInput() {
    const [name, setName] = useState('');

    const handleChange = (e) => {
        // We can format, validate, or intercept the typing instantly!
        setName(e.target.value.toUpperCase()); 
    };

    return (
        <form>
            <input 
                type="text" 
                value={name} // Driven strictly by React
                onChange={handleChange} 
            />
        </form>
    );
}

Pros:

  • Instant validation (disabling buttons if input is invalid).
  • Enforcing input formats (like forcing uppercase, as shown above).
  • Dynamic inputs (conditionally showing other fields based on this input).

2. Uncontrolled Components (The DOM handles the state)

In an uncontrolled component, form data is handled directly by the DOM, mimicking traditional HTML behavior.

Instead of tracking every single keystroke with state, you use a ref (useRef) to grab the data directly from the DOM only when you actually need it (usually upon form submission).

import { useRef } from 'react';

function UncontrolledInput() {
    const nameRef = useRef(null);

    const handleSubmit = (e) => {
        e.preventDefault();
        // We ONLY access the value right when the user clicks submit
        alert(`Submitted: ${nameRef.current.value}`); 
    };

    return (
        <form onSubmit={handleSubmit}>
            <input 
                type="text" 
                ref={nameRef} // Tells React to track this DOM node
                defaultValue="Abhay" // Used instead of 'value' for initial state
            />
            <button type="submit">Submit</button>
        </form>
    );
}

Pros:

  • Less code (no useState or onChange boilerplate).
  • Faster execution (typing does not trigger a React component re-render).
  • Easier integration with non-React third-party APIs or vanilla JS libraries that expect direct DOM manipulation.

Summary

  • Use Controlled for real-time validation, dynamic UI changes based on input, and strictly keeping React as the source of truth. (This is generally the recommended approach in React).
  • Use Uncontrolled if the form is incredibly simple or if you need to wrap legacy vanilla JS components.