Controlled vs Uncontrolled
Definition
A Controlled component is a form element whose value is entirely driven by React state. An Uncontrolled component is a form element that maintains its own internal HTML state, accessed via a React `ref`.
Explain Like I'm New
Imagine a steering wheel. A 'Controlled' car is a modern self-driving car: React's computer (state) has its hands firmly on the wheel 100% of the time. It knows exactly where the wheel is at every millisecond. An 'Uncontrolled' car is a manual car: the driver (the DOM) holds the wheel. If React wants to know where the wheel is, it has to physically look at the driver (using a `ref`) and ask 'Hey, what's your current value?'.
Real World Example
If you want a login form where the 'Submit' button disables automatically until the password is 8 characters long, you MUST use a Controlled component, because React needs to know the password value at every single keystroke. If you just have a massive survey form and only care about the values when the user finally hits 'Submit', you can use Uncontrolled components for better performance.
Common Use Cases
- •Controlled: Instant form validation, disabling submit buttons, formatting text as the user types (like adding dashes to phone numbers)
- •Uncontrolled: Integrating with non-React libraries (like a jQuery datepicker), or massive forms where re-rendering on every keystroke causes lag
Interactive Example
import React, { useState, useRef } from 'react'; export default function FormExample() { // For the Controlled Input const [name, setName] = useState(''); // For the Uncontrolled Input const ageRef = useRef(null); const handleSubmit = (e) => { e.preventDefault(); // Controlled: We already know the value because it's in State! console.log("Controlled Name:", name); // Uncontrolled: We have to manually ask the DOM for the value. console.log("Uncontrolled Age:", ageRef.current.value); }; return ( <form onSubmit={handleSubmit} className="flex flex-col gap-4"> <div> <h3>Controlled Input</h3> {/* React is the boss here. The value is locked to State. */} <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Enter name (React tracks every keystroke!)" className="w-full p-2 border" /> <p className="text-sm text-gray-500">Current state: {name}</p> </div> <div> <h3>Uncontrolled Input</h3> {/* The DOM is the boss here. We only use defaultValue to start it. */} <input type="number" ref={ageRef} defaultValue="18" placeholder="Enter age (React ignores keystrokes)" className="w-full p-2 border" /> </div> <button type="submit" className="bg-blue-500 text-white p-2 rounded"> Submit Form </button> </form> ); }
Interview Questions
basic
- What is a Controlled Component?
- How do you access the value of an Uncontrolled Component?
intermediate
- Why does a Controlled input need both a `value` prop and an `onChange` handler?
- What happens if you provide a `value` prop to an input without an `onChange` handler?
advanced
- How does the `defaultValue` prop differ from the `value` prop?
- Can a component switch between being controlled and uncontrolled during its lifecycle?
trick
- Is it bad practice to use Uncontrolled components?