Skip to content
Back to skills

React State Machine

ASecurity

Building reusable React state machine skills with XState v5 and the actor model

  • 74 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 6, 2026
developmenttypescriptgoreactnextjstestingdebuggingapiperformancedocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 12 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add bobmatnyc/claude-mpm-skills --skill react-state-machine --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of React State Machine?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for React State Machine
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bobmatnyc-react-state-machine/badge)](https://www.skillsdirectory.com/skills/bobmatnyc-react-state-machine)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: react-state-machine
description: "Building reusable React state machine skills with XState v5 and the actor model"
user-invocable: false
disable-model-invocation: true
version: 1.0.1
category: development
author: Claude MPM Team
license: MIT
progressive_disclosure:
  entry_point:
    summary: "Build type-safe, visualizable React state machines using XState v5's actor model for predictable UI behavior"
    when_to_use: "Complex async flows, multi-step forms, modal animations, media players, boolean flag explosion, defensive coding patterns"
    quick_start: "1. Define states/events with setup() 2. Use promise actors for async 3. useMachine for simple, useActorRef+useSelector for performance 4. Test with createActor 5. Visualize in Stately Studio"
  references:
    - xstate-v5-patterns.md
    - react-integration.md
    - skills-architecture.md
    - testing-patterns.md
    - decision-trees.md
    - real-world-patterns.md
    - error-handling.md
    - performance.md
    - persistence-hydration.md
    - migration-guide.md
    - composition-patterns.md
context_limit: 700
tags:
  - react
  - state-machine
  - xstate
  - actors
  - async
  - forms
  - ui-logic
requires_tools: []
---

# React State Machines with XState v5

## Overview

State machines make impossible states unrepresentable by modeling UI behavior as explicit states, transitions, and events. XState v5 (2.5M+ weekly npm downloads) unifies state machines with the actor model—every machine is an independent entity with its own lifecycle, enabling sophisticated composition patterns.

## When to Use This Skill

**Trigger patterns:**
- Boolean flag explosion: multiple `isLoading`, `isError`, `isSuccess` flags
- Implicit states: writing `if (isLoading && !isError && data)` to derive mode
- Defensive coding: guards before state updates to prevent invalid transitions
- Timing coordination: timeouts, delays, debouncing across states
- State dependencies: one state depends on another to update correctly

**Do not use for:**
- Simple boolean toggles with no async (useState is simpler)
- Single form fields with basic validation (useReducer suffices)
- Server state caching (React Query/TanStack Query handles this)
- Static data transformations (useMemo is better)
- Simple counters or toggles (useState is clearer)

**See decision-trees.md for comprehensive decision guidance**

## Core Mental Model

**Finite states** represent modes of behavior: `idle`, `loading`, `success`, `error`. A component can only be in ONE state at a time.

**Context (extended state)** stores quantitative data that doesn't define distinct states. The finite state says "playing"; context says *what* at *what volume*.

**Events** trigger transitions between states. Events are objects: `{ type: 'SUBMIT', data: formData }`.

**Guards** conditionally allow/block transitions: `{ guard: 'hasValidInput' }`.

**Actions** are fire-and-forget side effects during transitions or state entry/exit.

**Invoked actors** are long-running processes (API calls, subscriptions) with lifecycle management and cleanup.

## Quick Start: XState v5 setup() Pattern

```typescript
import { setup, assign, fromPromise } from 'xstate';

const fetchMachine = setup({
  types: {
    context: {} as { data: User | null; error: string | null },
    events: {} as 
      | { type: 'FETCH'; userId: string }
      | { type: 'RETRY' }
  },
  actors: {
    fetchUser: fromPromise(async ({ input, signal }) => {
      const res = await fetch(`/api/users/${input.userId}`, { signal });
      if (!res.ok) throw new Error(res.statusText);
      return res.json();
    })
  },
  actions: {
    setData: assign({ data: ({ event }) => event.output }),
    setError: assign({ error: ({ event }) => event.error.message })
  }
}).createMachine({
  id: 'fetch',
  initial: 'idle',
  context: { data: null, error: null },
  states: {
    idle: { on: { FETCH: 'loading' } },
    loading: {
      invoke: {
        src: 'fetchUser',
        input: ({ event }) => ({ userId: event.userId }),
        onDone: { target: 'success', actions: 'setData' },
        onError: { target: 'failure', actions: 'setError' }
      }
    },
    success: { on: { FETCH: 'loading' } },
    failure: { on: { RETRY: 'loading' } }
  }
});
```

## React Integration Decision Tree

| Use Case | Hook | Why |
|----------|------|-----|
| Simple component state | `useMachine` | Straightforward, re-renders on all changes |
| Performance-critical | `useActorRef` + `useSelector` | Selective re-renders only |
| Global/shared state | `createActorContext` | React Context integration |

**Basic pattern:**
```typescript
import { useMachine } from '@xstate/react';

function Toggle() {
  const [snapshot, send] = useMachine(toggleMachine);
  return (
    <button onClick={() => send({ type: 'TOGGLE' })}>
      {snapshot.matches('inactive') ? 'Off' : 'On'}
    </button>
  );
}
```

**Performance pattern:**
```typescript
import { useActorRef, useSelector } from '@xstate/react';

const selectCount = (s) => s.context.count;
const selectLoading = (s) => s.matches('loading');

function Counter() {
  const actorRef = useActorRef(counterMachine);
  const count = useSelector(actorRef, selectCount);
  const loading = useSelector(actorRef, selectLoading);
  // Only re-renders when count or loading changes
}
```

## Anti-Patterns to Avoid

❌ **State explosion**: Flat states for orthogonal concerns. Use parallel states instead.

❌ **Sending events from actions**: Never `send()` inside `assign`. Use `raise` for internal events.

❌ **Impure guards**: Guards must be pure—no side effects, no external mutations.

❌ **Subscribing to entire state**: Use focused selectors with `useSelector`.

❌ **Not memoizing model**:
```typescript
// WRONG
const model = Model.fromJson(layout);  // New model every render

// CORRECT
const modelRef = useRef(Model.fromJson(layout));
```

## Navigation to References

### Core Patterns
- **xstate-v5-patterns.md**: Complete v5 API, statecharts (hierarchy/parallel/history), promise actors
- **react-integration.md**: useMachine vs useActorRef, Context patterns, side effect handling
- **testing-patterns.md**: Unit testing, mocking actors, visualization debugging

### Decision Making & Best Practices
- **decision-trees.md**: When to use state machines vs useState/useReducer/React Query, machine splitting strategies
- **real-world-patterns.md**: Complete examples - auth flows, file uploads, wizards, undo/redo, shopping carts
- **error-handling.md**: Error boundaries, retry strategies, circuit breakers, graceful degradation
- **performance.md**: Selector memoization, React.memo integration, machine splitting for performance

### Advanced Topics
- **persistence-hydration.md**: localStorage persistence, SSR/Next.js hydration, snapshot serialization
- **migration-guide.md**: Step-by-step migration from useState/useReducer with before/after examples
- **composition-patterns.md**: Actor communication, machine composition, higher-order machines, systemId
- **skills-architecture.md**: Input/output parameterization, library structure

## Key Reminders

1. **setup() is the v5 way**: Strong TypeScript inference, actor registration, action definitions
2. **Invoke for async, actions for sync**: Actions are fire-and-forget; invoked actors have lifecycle
3. **Finite states for modes, context for data**: Don't create states for every data variation
4. **Visualize first**: Stately Studio (stately.ai/editor) makes machines living documentation

## Red Flags

- More than 3-4 boolean flags → Need state machine
- Writing `if (a && !b && c)` to determine mode → States should be explicit
- Bugs from invalid state combinations → Machine prevents impossible states
- Can't explain state transitions to stakeholders → Visualization solves this

## Related Skills

- **react**: Parent skill for React patterns
- **nextjs**: Server/client state coordination
- **test-driven-development**: Test machines with createActor before UI integration

Files in this skill

  • SKILL.md7.8 KB
  • references/composition-patterns.md12.7 KB
  • references/decision-trees.md7.2 KB
  • references/error-handling.md15.1 KB
  • references/migration-guide.md13.4 KB
  • references/performance.md12.6 KB
  • references/persistence-hydration.md12.9 KB
  • references/react-integration.md14.2 KB
  • references/real-world-patterns.md23.3 KB
  • references/skills-architecture.md10.6 KB
  • references/testing-patterns.md11.4 KB
  • references/xstate-v5-patterns.md9.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…