BACK
Use casesLoad state machine — idle/loading/success/error
Use cases · 43

Load state machine — idle/loading/success/error

Pattern

Every async request passes through explicit states: loadingsuccess(data) or error(message). This is a discriminated union — a typed state machine, not three separate booleans.

The problem it solves

Separate isLoading, data, error fields are easy to get out of sync. After a failure someone forgot to reset data, and the UI shows old data with an error banner on top. Impossible flag combinations spread like weeds.

Operators and why they matter

  • startWith({kind: 'loading'}) — emit the loading state immediately, BEFORE the response.
  • map(data => ({kind: 'success', data})) — a successful response becomes a success state.
  • catchError(error => of({kind: 'error', error})) — a failure becomes an error state, WITHOUT killing the outer stream.

Gotchas

  • tap with manual this.isLoading=true/false flags — harder to test than state-as-data.
  • catchError outside the trigger stream — one error stops all future reloads. Put it INSIDE switchMap.
  • Don't mix idle and loading. idle = "no request yet". loading = "a request is in flight". Different states.

What you get

The UI gets one typed state and renders it with a switch. No more impossible combinations.

script.ts // TypeScript
CONSOLE · Console output
Hit Run to see the result...