Week 9

useReducer

Context API

Error Boundaries

React Hook Form

Practice

Assignment

Front end Track

Content

Let’s get practical

Exercise 1: Refactor a Form with useReducer

Difficulty: Medium Concepts: useReducer, reducer function shape, actions and dispatch, modelling form state

Take the controlled form below — written with multiple useState calls — and refactor it to use a single useReducer.

Starting point — paste this into a new component file:

import { useState } from 'react';

export default function AddConcertForm() {
  const [artist, setArtist] = useState('');
  const [venue, setVenue] = useState('');
  const [date, setDate] = useState('');
  const [ticketPrice, setTicketPrice] = useState('');
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [submitted, setSubmitted] = useState(false);

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setIsSubmitting(true);
    setError(null);

    try {
      // Simulate an API call
      await new Promise((resolve) => setTimeout(resolve, 1000));
      if (Math.random() < 0.3) throw new Error('Server error — try again');
      setSubmitted(true);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error');
    } finally {
      setIsSubmitting(false);
    }
  }

  if (submitted) {
    return <p>Concert added!</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="artist">Artist</label>
        <input
          id="artist"
          value={artist}
          onChange={(e) => setArtist(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="venue">Venue</label>
        <input
          id="venue"
          value={venue}
          onChange={(e) => setVenue(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="date">Date</label>
        <input
          id="date"
          type="date"
          value={date}
          onChange={(e) => setDate(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="ticketPrice">Ticket Price</label>
        <input
          id="ticketPrice"
          type="number"
          value={ticketPrice}
          onChange={(e) => setTicketPrice(e.target.value)}
        />
      </div>
      {error && <p role="alert">{error}</p>}
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Saving...' : 'Add Concert'}
      </button>
    </form>
  );
}

Requirements:

Hints:

Exercise 2: Share State with Context

Difficulty: Easy Concepts: createContext, useContext, Provider, consuming context in a child component

Build a small app with a theme toggle. The toggle lives in one component, and the current theme is displayed in another — without passing props between them.

Requirements:

Hints:

Exercise 3: Catch Errors with an Error Boundary

Difficulty: Easy Concepts: Error boundaries, fallback UI, what gets caught and what doesn't

Add an Error Boundary around a component that throws during rendering, so the rest of the page stays visible.

Requirements:

Hints:

Exercise 4: Your First React Hook Form

Difficulty: Easy Concepts: useForm, register, handleSubmit, formState errors, validation rules

Build a simple contact form from scratch using React Hook Form. No useState, no onChange handlers — just register, handleSubmit, and errors.

Requirements:

Hints:


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.