react-state-machines

安装量: 85
排名: #9344

安装

npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill react-state-machines

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 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:

import { useMachine } from '@xstate/react';

function Toggle() { const [snapshot, send] = useMachine(toggleMachine); return ( ); }

Performance pattern:

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:

// 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 setup() is the v5 way: Strong TypeScript inference, actor registration, action definitions Invoke for async, actions for sync: Actions are fire-and-forget; invoked actors have lifecycle Finite states for modes, context for data: Don't create states for every data variation 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

返回排行榜