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.