CodeOath
← All posts
React75 min total · 17 parts

React Fundamentals: Components, Hooks, and the Virtual DOM

Contents — Part 7 of 17: Forms and Controlled Components
Part 7 of 17 · ~1 min

Forms and Controlled Components

A controlled input's value is driven entirely by React state — the DOM input never has a value React doesn't already know about:

function NameForm() {
  const [name, setName] = useState("");
  return (
    <input value={name} onChange={(e) => setName(e.target.value)} />
  );
}

Every keystroke fires onChange, updates state, and React re-renders the input with that state as its value — from the outside, it looks instantaneous. The alternative, an uncontrolled input, lets the DOM manage its own value and you read it out on demand via a ref (inputRef.current.value) — useful for simple forms or integrating with non-React code, but you lose the ability to validate or react to every keystroke.

Multiple fields: one object vs. one useState per field

function SignupForm() {
  const [form, setForm] = useState({ email: "", password: "" });

  function handleChange(e) {
    const { name, value } = e.target;
    setForm((prev) => ({ ...prev, [name]: value }));
  }

  return (
    <>
      <input name="email" value={form.email} onChange={handleChange} />
      <input name="password" value={form.password} onChange={handleChange} />
    </>
  );
}

A single object with one generic handleChange scales better than a separate useState per field once a form has more than two or three inputs — computed key ([name]: value) lets one handler cover every field, matched by each input's name attribute. For anything beyond a simple form (validation, touched/error state, nested fields), a dedicated form library (React Hook Form, Formik) is the practical real-world choice rather than hand-rolling all of this.