Chapter 3 of 4
Controlled Inputs
Binding form fields to state so React is the single source of truth.
A controlled input takes its value from state and reports changes back through onChange. React holds the truth and the DOM just displays it.
function NameField() {
const [name, setName] = useState("");
return (
<input
value={name}
onChange={(event) => setName(event.target.value)}
/>
);
}Because the value lives in state, you can validate it, transform it, or reset it from anywhere.
onChange={(event) => setName(event.target.value.toUpperCase())}The different field types
// Text, email, number, textarea: use value
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<textarea value={bio} onChange={(e) => setBio(e.target.value)} />
// Checkbox: use checked, and read event.target.checked
<input
type="checkbox"
checked={acceptsTerms}
onChange={(e) => setAcceptsTerms(e.target.checked)}
/>
// Select: value goes on the select, not the option
<select value={country} onChange={(e) => setCountry(e.target.value)}>
<option value="uk">United Kingdom</option>
<option value="de">Germany</option>
</select>One state object for a whole form
Rather than a useState per field, many forms keep one object and a shared change handler. The name attribute picks the field to update.
const [form, setForm] = useState({ name: "", email: "" });
function handleChange(event) {
const { name, value } = event.target;
setForm((previous) => ({ ...previous, [name]: value }));
}
<input name="name" value={form.name} onChange={handleChange} />
<input name="email" value={form.email} onChange={handleChange} />