Questions
This form uses an uncontrolled input. Refactor it to be a controlled component.
A developer has built a simple login form with an input field for the username and a submit button. They’ve implemented the username input as an uncontrolled component, meaning its value is managed by the DOM itself, and they access it using a ref only when the form is submitted.
Now, they want to add two new features:
- Real-time validation: Display an error message if the username input is empty.
- Dynamic button state: Disable the submit button if the username input is empty.
They are struggling to implement these features effectively because they can’t easily get the input’s value in real-time.
You’ve been given the LoginForm component. Your task is to refactor the username input from an uncontrolled component to a controlled component.
After refactoring, implement the real-time validation and dynamic button state:
- Show an error message “Username cannot be empty” if the input is empty.
- Disable the “Submit” button if the input is empty.
import React, { useRef } from 'react';
export default function LoginForm() {
const usernameInputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
const username = usernameInputRef.current.value;
if (username.trim() === '') {
alert('Username cannot be empty!');
return;
}
alert(`Submitting username: ${username}`);
// In a real app, you'd send this to an API
};
return (
<form onSubmit={handleSubmit} style={{ padding: '20px', border: '1px solid #ccc' }}>
<h2>Login</h2>
<label>
Username:
{/* THE BUG: This is an uncontrolled input.
Its value is managed by the DOM, not React state. */}
<input type="text" ref={usernameInputRef} />
</label>
{/* No real-time validation or dynamic button state */}
<button type="submit" style={{ marginLeft: '10px' }}>
Submit
</button>
</form>
);
} How Different Experience Levels Approach This
import React, { useRef } from 'react'; export default function LoginForm() { const usernameInputRef = useRef(null); const handleSubmit = (event) => { event.preventDefault(); const username = usernameInputRef.current.value; if (username.trim() === '') { alert('Username cannot be empty!'); return; } alert(`Submitting username: ${username}`); // In a real app, you'd send this to an API }; return ( <form onSubmit={handleSubmit} style={{ padding: '20px', border: '1px solid #ccc' }}> <h2>Login</h2> <label> Username: {/* THE BUG: This is an uncontrolled input. Its value is managed by the DOM, not React state. */} <input type="text" ref={usernameInputRef} /> </label> {/* No real-time validation or dynamic button state */} <button type="submit" style={{ marginLeft: '10px' }}> Submit </button> </form> ); }
import React, { useState } from 'react'; export default function LoginForm() { // FIX: Use useState to manage the input's value const [username, setUsername] = useState(''); const [error, setError] = useState(''); const handleUsernameChange = (event) => { const newValue = event.target.value; setUsername(newValue); // Real-time validation if (newValue.trim() === '') { setError('Username cannot be empty'); } else { setError(''); } }; const handleSubmit = (event) => { event.preventDefault(); if (username.trim() === '') { setError('Username cannot be empty'); // Final check on submit return; } alert(`Submitting username: ${username}`); }; // Determine if the button should be disabled const isSubmitDisabled = username.trim() === ''; return ( <form onSubmit={handleSubmit} style={{ padding: '20px', border: '1px solid #ccc' }}> <h2>Login</h2> <label> Username: {/* FIX: Bind value to state and provide onChange handler */} <input type="text" value={username} onChange={handleUsernameChange} /> </label> {/* Display real-time error message */} {error && <p style={{ color: 'red', fontSize: '0.8em' }}>{error}</p>} <button type="submit" style={{ marginLeft: '10px' }} disabled={isSubmitDisabled}> Submit </button> </form> ); }
- Context over facts: Explains when and why, not just what
- Real examples: Provides specific use cases from production experience
- Trade-offs: Acknowledges pros, cons, and decision factors
Practice Question
What is the primary characteristic of a controlled component in React?