#react #tutorial #intermediate

Day 6: Forms & Validation

Day 6: Forms & Validation

Dealing with user input is a core part of most apps. In React, we typically use Controlled Components.

Recap: Controlled Components

As we saw in Day 3, a controlled component is an input where the React state acts as the “single source of truth”.

const [email, setEmail] = useState('');
<input value={email} onChange={(e) => setEmail(e.target.value)} />

Handling Multiple Inputs

Imagine a signup form with First Name, Last Name, Email, and Password. Creating 4 separate useState hooks is fine, but it can get messy. We can use a single object for state.

function SignupForm() {
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
    email: '',
  });

  function handleChange(e) {
    // Dynamic key access: [e.target.name]
    setFormData({
      ...formData,
      [e.target.name]: e.target.value,
    });
  }

  return (
    <form>
      <input 
        name="firstName" 
        value={formData.firstName} 
        onChange={handleChange} 
        placeholder="First Name" 
      />
      <input 
        name="lastName" 
        value={formData.lastName} 
        onChange={handleChange} 
        placeholder="Last Name" 
      />
      <input 
        name="email" 
        value={formData.email} 
        onChange={handleChange} 
        placeholder="Email" 
      />
    </form>
  );
}

Form Submission

The default behavior of an HTML form submit is to reload the page. In React, we want to prevent that.

function handleSubmit(e) {
  e.preventDefault(); // Stop page reload
  console.log('Form Submitted:', formData);
  // Send formData to an API...
}

return <form onSubmit={handleSubmit}>...</form>

Validation

Validation is just logic checking your state.

function LoginForm() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  function handleSubmit(e) {
    e.preventDefault();
    if (!email.includes('@')) {
      setError('Invalid email address');
      return;
    }
    setError('');
    console.log('Login successful');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button type="submit">Login</button>
    </form>
  );
}

React Hook Form

For complex forms, manual state handling gets tedious. The community standard library is React Hook Form.

npm install react-hook-form
import { useForm } from "react-hook-form";

function App() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* "register" links the input to the hook */}
      <input {...register("firstName", { required: true })} />
      {errors.firstName && <span>This field is required</span>}
      
      <input type="submit" />
    </form>
  );
}

This library reduces re-renders and code amount significantly.


Homework for Day 6:

  1. Build a basic “Contact Us” form (Name, Email, Message).
  2. Validate that Name is not empty and Message is at least 10 characters long.
  3. Show error messages below the inputs.
  4. On valid submit, clear the form and show a “Success!” message.

Day 7 brings us to Global State with Context!