Skip to Content
Exercises01 ReactExercise: debouncing (Zod, tRPC, fetch in useEffect)

Exercise: debouncing (Zod, tRPC, fetch in useEffect)

Goal

Practice debouncing in three common places:

  1. Zod form validation on change
  2. tRPC “availability check” calls
  3. plain fetch inside useEffect for search/autocomplete

Part A — Debounced Zod validation (client-side UX)

Build (or extend) a form field (e.g. Email) that:

  • validates with Zod
  • validates on change, debounced
  • still validates on submit as the final gate

Acceptance criteria:

  • Validation does not run on every keystroke (it’s delayed).
  • Errors do not “flash” while the user is typing normally.
  • Clearing the field clears the error state appropriately.

Part B — Debounced tRPC availability check

Simulate an “is email taken?” check:

  • When the email looks valid, call a tRPC query (or a mocked function standing in for it).
  • Debounce the call.
  • Handle these states in the UI:
    • idle (no check yet)
    • checking
    • available
    • taken
    • error

Acceptance criteria:

  • Only the latest typed value can win (stale results must be ignored).
  • Changing the email cancels/invalidates the previous in-flight check.
  • No call is made for obviously invalid input (basic gating before calling).

Part C — Debounced fetch in useEffect (search/autocomplete)

Create a search box that:

  • triggers a fetch in an effect when the query changes
  • debounces the effect
  • handles cancellation/ignoring stale results (e.g. AbortController or a request id)

Acceptance criteria:

  • Typing quickly does not fire a request per keystroke.
  • Stale results never replace newer ones.
  • Empty query shows an intentional empty state.

Notes (keep it simple)

  • Debouncing is about timing; stale-result handling is about correctness.
  • Prefer gating before calling the network (format checks, min length, etc.).
Last updated on