Course outline · 0% complete

0/28 lessons0%

Course overview →

Multi-field forms and submit

lesson 6-2 · ~12 min · 17/28

Multi-field forms and submit

A signup form has several fields. You could call useState per field, which is fine for two or three. Past that, one object keeps them together, updated with the spread pattern from lesson 4-3:

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

  function update(field, value) {
    setForm({ ...form, [field]: value });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={form.email}
             onChange={e => update("email", e.target.value)} />
      <input type="password" value={form.password}
             onChange={e => update("password", e.target.value)} />
      <button>Sign up</button>
    </form>
  );
}

{ ...form, [field]: value } copies the object and overwrites one field, using the computed property name syntax from Advanced JavaScript.

Handling submit

A browser submits forms by navigating to a new page, a full reload. In a React app you almost never want that, so the submit handler's first line stops it:

function handleSubmit(e) {
  e.preventDefault();
  const errors = validate(form);
  if (errors.length > 0) {
    setErrors(errors);
    return;
  }
  // send form to the server (Unit 7 covers fetching)
}

e.preventDefault() is the same DOM method from Web Development Fundamentals. Notice validate is a plain function taking the form object and returning an array of error strings. Keeping validation out of the component makes it testable, and it is exactly the kind of logic we CAN run right here.

Code exercise · javascript

Your turn. Complete validate(form) so it returns an array of error strings: "Email is required" when email is blank, otherwise "Email must contain @" when it lacks an @, plus "Password must be 8+ characters" when the password is shorter than 8. Return [] when everything passes.

Quiz

Why does a React submit handler start with e.preventDefault()?

Problem

In the update helper, setForm({ ...form, [field]: value }), what would go wrong if you wrote setForm({ [field]: value }) without the spread?