React Advanced

State Machines with XState

Finite state machines, guards, actions, services, and complex state logic.

Advertisement

State Machines with XState

Finite state machines, guards, actions, services, and complex state logic.

Overview

State machines eliminate impossible states and make complex state logic predictable.

Key Concepts

  • States — Finite set of states the system can be in
  • Events — Trigger transitions between states
  • Guards — Conditions that determine valid transitions
  • Actions — Side effects triggered by transitions
  • Services — Async operations invoked by the machine

Code Examples

import { createMachine, assign } from 'xstate';
import { useMachine } from '@xstate/react';

const fetchMachine = createMachine({
  id: 'fetch',
  initial: 'idle',
  context: { data: null, error: null },
  states: {
    idle: {
      on: { FETCH: 'loading' }
    },
    loading: {
      invoke: {
        src: 'fetchData',
        onDone: { target: 'success', actions: assign({ data: (_, event) => event.data }) },
        onError: { target: 'failure', actions: assign({ error: (_, event) => event.data }) }
      }
    },
    success: {
      on: { FETCH: 'loading' }
    },
    failure: {
      on: { RETRY: 'loading' }
    }
  }
}, {
  services: {
    fetchData: async () => {
      const response = await fetch('/api/data');
      return response.json();
    }
  }
});

function DataFetcher() {
  const [state, send] = useMachine(fetchMachine);

  return (
    <div>
      {state.matches('idle') && <button onClick={() => send('FETCH')}>Fetch</button>}
      {state.matches('loading') && <p>Loading...</p>}
      {state.matches('success') && <pre>{JSON.stringify(state.context.data, null, 2)}</pre>}
      {state.matches('failure') && (
        <div>
          <p>Error: {state.context.error?.message}</p>
          <button onClick={() => send('RETRY')}>Retry</button>
        </div>
      )}
    </div>
  );
}

Practice

Model a multi-step form wizard with XState including validation and back navigation.