Controlled components are components whose state is managed by React through state. Uncontrolled components are components whose state is managed directly by the DOM, without React’s involvement.
✅ Controlled components:
✅ Uncontrolled components:
Key rule: In most cases, use controlled components for better control and validation! 🎯
Imagine you’re driving a car. Controlled components are like adaptive cruise control that constantly monitors speed. Uncontrolled components are like mechanical cruise control that simply keeps the gas pedal pressed.
Controlled components are components whose value is controlled by React:
// Controlled component
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
Uncontrolled components are components whose value is managed directly by the DOM:
// Uncontrolled component
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = () => {
console.log(inputRef.current.value);
};
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleSubmit}>Get value</button>
</div>
);
}
Characteristic | Controlled | Uncontrolled |
---|---|---|
State management | Through React state | Through DOM |
Validation | Real-time | On submit |
Code | More | Less |
Flexibility | High | Limited |
Performance | Can be lower | Usually higher |
✅ Use controlled components when:
// Example with validation
function EmailInput() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const validateEmail = (value) => {
if (!value.includes('@')) {
setError('Invalid email');
} else {
setError('');
}
};
return (
<div>
<input
type="email"
value={email}
onChange={(e) => {
setEmail(e.target.value);
validateEmail(e.target.value);
}}
style={{ borderColor: error ? 'red' : 'green' }}
/>
{error && <span style={{ color: 'red' }}>{error}</span>}
</div>
);
}
✅ Use uncontrolled components when:
// Example with third-party library integration
function DatePicker() {
const dateRef = useRef(null);
useEffect(() => {
// Initialize third-party library
new SomeDatePickerLibrary(dateRef.current);
}, []);
return <input type="text" ref={dateRef} />;
}
// ❌ Error - mixing controlled and uncontrolled
function BadComponent() {
const [value, setValue] = useState('');
return (
// Both value and defaultValue specified - conflict!
<input
value={value}
defaultValue="initial"
onChange={(e) => setValue(e.target.value)}
/>
);
}
// ✅ Correct - choose one approach
function GoodControlled() {
const [value, setValue] = useState('initial');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
function GoodUncontrolled() {
return <input defaultValue="initial" />;
}
// ❌ Wrong - when control is needed
function BadForm() {
// Impossible to validate or reset form
return (
<form>
<input type="text" name="username" ref={useRef()} />
<input type="email" name="email" ref={useRef()} />
<button type="submit">Submit</button>
</form>
);
}
// ✅ Correct - when control is needed
function GoodForm() {
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// Validation and data submission
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button type="submit">Submit</button>
</form>
);
}
Controlled and uncontrolled components are like two different driving styles! 🚗
When to choose what:
Practical rule: Start with controlled components - they solve 90% of form tasks! If you encounter integration difficulties, then consider uncontrolled ones.
Understanding these concepts will help you create more predictable and user-friendly forms in your React applications! 💪
Want more useful React articles? Subscribe to EasyAdvice, bookmark the site and level up every day! 🚀