Top Related Projects
Actor-based state management & orchestration for complex app logic.
A JS library for predictable global state management
Simple, scalable state management.
Build forms in React, without the tears 😭
🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
Quick Overview
XState is a JavaScript and TypeScript library for creating finite state machines and statecharts. It provides a powerful and expressive way to model complex application logic, making it easier to manage and reason about application states and transitions.
Pros
- Helps manage complex application logic with a clear, visual representation
- Provides type safety and autocompletion when used with TypeScript
- Supports both synchronous and asynchronous state transitions
- Integrates well with popular frameworks like React, Vue, and Svelte
Cons
- Steep learning curve for developers unfamiliar with state machines and statecharts
- Can be overkill for simple applications or components
- Requires additional tooling for optimal visualization and debugging
- May increase bundle size for smaller projects
Code Examples
- Creating a simple toggle machine:
import { createMachine, interpret } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: { on: { TOGGLE: 'active' } },
active: { on: { TOGGLE: 'inactive' } }
}
});
const toggleService = interpret(toggleMachine).start();
toggleService.send('TOGGLE'); // Transitions to 'active' state
- Using guards to conditionally transition:
const lightMachine = createMachine({
id: 'light',
initial: 'green',
context: { timer: 0 },
states: {
green: {
on: {
TIMER: [
{ target: 'yellow', cond: (context) => context.timer >= 30 }
]
}
},
yellow: {
on: { TIMER: 'red' }
},
red: {
on: { TIMER: 'green' }
}
}
});
- Integrating with React using the
useMachine
hook:
import { useMachine } from '@xstate/react';
function ToggleComponent() {
const [state, send] = useMachine(toggleMachine);
return (
<button onClick={() => send('TOGGLE')}>
{state.value === 'inactive' ? 'Turn On' : 'Turn Off'}
</button>
);
}
Getting Started
To start using XState in your project:
-
Install XState:
npm install xstate
-
Import and create a machine:
import { createMachine, interpret } from 'xstate'; const machine = createMachine({ id: 'example', initial: 'idle', states: { idle: { on: { START: 'running' } }, running: { on: { STOP: 'idle' } } } }); const service = interpret(machine).start(); service.send('START'); console.log(service.state.value); // 'running'
-
For React integration, install the React package:
npm install @xstate/react
Competitor Comparisons
Actor-based state management & orchestration for complex app logic.
Pros of XState
- Robust state management library with support for complex state machines
- Extensive documentation and active community support
- Visual editor (XState Viz) for designing and debugging state machines
Cons of XState
- Steeper learning curve for developers new to state machines
- Can be overkill for simple state management needs
- Larger bundle size compared to simpler state management solutions
Code Comparison
XState:
import { createMachine, interpret } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: { on: { TOGGLE: 'active' } },
active: { on: { TOGGLE: 'inactive' } }
}
});
const toggleService = interpret(toggleMachine).start();
toggleService.send('TOGGLE');
Both repositories appear to be the same project, so there isn't a distinct code comparison to make. The XState library provides a powerful and flexible approach to state management using finite state machines and statecharts.
A JS library for predictable global state management
Pros of Redux
- Simpler learning curve for developers familiar with JavaScript
- Extensive ecosystem with many middleware options and tools
- Better suited for large-scale applications with complex data flows
Cons of Redux
- Requires more boilerplate code for setup and state management
- Can lead to overly complex state structures in smaller applications
- Less intuitive for handling asynchronous operations without additional middleware
Code Comparison
Redux:
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
XState:
const counterMachine = createMachine({
initial: 'active',
context: { count: 0 },
states: {
active: {
on: {
INCREMENT: { actions: assign({ count: (ctx) => ctx.count + 1 }) },
DECREMENT: { actions: assign({ count: (ctx) => ctx.count - 1 }) }
}
}
}
})
XState provides a more structured approach to state management using finite state machines, which can be beneficial for complex workflows and UI interactions. It offers better visualization tools and can handle side effects more elegantly. However, it may have a steeper learning curve for developers unfamiliar with state machine concepts.
Simple, scalable state management.
Pros of MobX
- Simpler learning curve and less boilerplate code
- More flexible and less opinionated about state structure
- Better performance for large-scale applications with complex state
Cons of MobX
- Less predictable state changes due to mutable state
- Harder to debug and trace state changes
- Lack of built-in support for complex state machines and transitions
Code Comparison
MobX:
import { makeObservable, observable, action } from "mobx";
class Counter {
count = 0;
constructor() {
makeObservable(this, {
count: observable,
increment: action
});
}
increment() {
this.count++;
}
}
XState:
import { createMachine, interpret } from "xstate";
const counterMachine = createMachine({
id: "counter",
initial: "idle",
context: { count: 0 },
states: {
idle: {
on: {
INCREMENT: {
actions: (context) => context.count++
}
}
}
}
});
Both MobX and XState are popular state management libraries, but they have different approaches. MobX focuses on reactive programming and mutable state, while XState emphasizes state machines and declarative state transitions. The choice between them depends on the specific needs of your project and your preferred programming paradigm.
Build forms in React, without the tears 😭
Pros of Formik
- Specifically designed for form handling, making it more intuitive for form-related tasks
- Lightweight and focused, resulting in a smaller bundle size
- Easier learning curve for developers familiar with React forms
Cons of Formik
- Limited to form management, lacking broader state management capabilities
- Less flexible for complex, multi-step form scenarios
- May require additional libraries for advanced form validation
Code Comparison
Formik:
<Formik
initialValues={{ email: '', password: '' }}
onSubmit={(values) => console.log(values)}
>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="email" type="email" />
<Field name="password" type="password" />
<button type="submit">Submit</button>
</form>
)}
</Formik>
XState:
const formMachine = createMachine({
initial: 'idle',
states: {
idle: { on: { SUBMIT: 'submitting' } },
submitting: {
invoke: {
src: 'submitForm',
onDone: 'success',
onError: 'error'
}
},
success: {},
error: {}
}
});
XState offers a more comprehensive state management solution, suitable for complex applications beyond form handling. It provides a clear visualization of application states and transitions, making it easier to manage intricate workflows. However, it may have a steeper learning curve and could be considered overkill for simpler form scenarios where Formik excels.
🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
Pros of TanStack Query
- Specialized for data fetching and caching, offering optimized performance for API interactions
- Automatic background refetching and stale-while-revalidate functionality
- Simpler API for common data fetching scenarios
Cons of TanStack Query
- Limited to data management, not suitable for complex application state
- Steeper learning curve for advanced features and configurations
- Less flexibility for custom state transitions and side effects
Code Comparison
XState:
const fetchMachine = createMachine({
initial: 'idle',
states: {
idle: { on: { FETCH: 'loading' } },
loading: { invoke: { src: fetchData, onDone: 'success', onError: 'failure' } },
success: {},
failure: {}
}
});
TanStack Query:
const { data, isLoading, error } = useQuery('userData', fetchUserData);
XState provides a more explicit state machine approach, while TanStack Query offers a simpler API for common data fetching scenarios. XState is more versatile for complex state management, whereas TanStack Query excels in data fetching and caching specifically.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Actor-based state management & orchestration for complex app logic. â Documentation
XState is a state management and orchestration solution for JavaScript and TypeScript apps. It has zero dependencies, and is useful for frontend and backend application logic.
It uses event-driven programming, state machines, statecharts, and the actor model to handle complex logic in predictable, robust, and visual ways. XState provides a powerful and flexible way to manage application and workflow state by allowing developers to model logic as actors and state machines.
⨠Create state machines visually in Stately Studio â state.new
â¡ï¸ Create state machines with the Stately Editor
ð¥ Download our VS Code extension
ð Inspired by the SCXML specification
ð¬ Chat on the Stately Discord Community
âï¸ Browse through the many XState examples
Templates
Get started by forking one of these templates on CodeSandbox:
Template | |
---|---|
|
|
|
|
|
|
|
Super quick start
npm install xstate
import { createMachine, createActor, assign } from 'xstate';
// State machine
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
context: {
count: 0
},
states: {
inactive: {
on: {
TOGGLE: { target: 'active' }
}
},
active: {
entry: assign({ count: ({ context }) => context.count + 1 }),
on: {
TOGGLE: { target: 'inactive' }
}
}
}
});
// Actor (instance of the machine logic, like a store)
const toggleActor = createActor(toggleMachine);
toggleActor.subscribe((state) => console.log(state.value, state.context));
toggleActor.start();
// => logs 'inactive', { count: 0 }
toggleActor.send({ type: 'TOGGLE' });
// => logs 'active', { count: 1 }
toggleActor.send({ type: 'TOGGLE' });
// => logs 'inactive', { count: 1 }
Stately Studio
- Visually create, edit, and collaborate on state machines
- Export to many formats, including XState v5
- Test path & documentation autogeneration
- Deploy to Stately Sky
- Generate & modify machines with Stately AI
Why?
Statecharts are a formalism for modeling stateful, reactive systems. This is useful for declaratively describing the behavior of your application, from the individual components to the overall application logic.
Read ð½ the slides (ð¥ video) or check out these resources for learning about the importance of finite state machines and statecharts in user interfaces:
- Statecharts - A Visual Formalism for Complex Systems by David Harel
- The World of Statecharts by Erik Mogensen
Packages
Package | Description |
---|---|
ð¤ xstate | Core finite state machine and statecharts library + interpreter |
ð @xstate/graph | Graph traversal and model-based testing utilities using XState |
âï¸ @xstate/react | React hooks and utilities for using XState in React applications |
ð @xstate/vue | Vue composition functions and utilities for using XState in Vue applications |
ð· @xstate/svelte | Svelte utilities for using XState in Svelte applications |
ð¥ @xstate/solid | Solid hooks and utilities for using XState in Solid applications |
ð @statelyai/inspect | Inspection utilities for XState |
ðª @xstate/store | Small library for simple state management |
Finite State Machines
Code | Statechart | ||||
---|---|---|---|---|---|
|
Open in Stately Studio |
Hierarchical (Nested) State Machines
Code | Statechart |
---|---|
|
Open in Stately Studio |
Parallel State Machines
Code | Statechart |
---|---|
|
Open in Stately Studio |
History States
Code | Statechart |
---|---|
|
Open in Stately Studio |
Sponsors
Special thanks to the sponsors who support this open-source project:
SemVer Policy
We understand the importance of the public contract and do not intend to release any breaking changes to the runtime API in a minor or patch release. We consider this with any changes we make to the XState libraries and aim to minimize their effects on existing users.
Breaking changes
XState executes much of the user logic itself. Therefore, almost any change to its behavior might be considered a breaking change. We recognize this as a potential problem but believe that treating every change as a breaking change is not practical. We do our best to implement new features thoughtfully to enable our users to implement their logic in a better, safer way.
Any change could affect how existing XState machines behave if those machines are using particular configurations. We do not introduce behavior changes on a whim and aim to avoid making changes that affect most existing machines. But we reserve the right to make some behavior changes in minor releases. Our best judgment of the situation will always dictate such changes. Please always read our release notes before deciding to upgrade.
TypeScript changes
We also reserve a similar right to adjust declared TypeScript definitions or drop support for older versions of TypeScript in a minor release. The TypeScript language itself evolves quickly and often introduces breaking changes in its minor releases. Our team is also continuously learning how to leverage TypeScript more effectively - and the types improve as a result.
For these reasons, it is impractical for our team to be bound by decisions taken when an older version of TypeScript was its latest version or when we didnât know how to declare our types in a better way. We wonât introduce declaration changes often - but we are more likely to do so than with runtime changes.
Packages
Most of the packages in the XState family declare a peer dependency on XState itself. Weâll be cautious about maintaining compatibility with already-released packages when releasing a new version of XState, but each release of packages depending on XState will always adjust the declared peer dependency range to include the latest version of XState. For example, you should always be able to update xstate
without @xstate/react
. But when you update @xstate/react
, we highly recommend updating xstate
too.
Top Related Projects
Actor-based state management & orchestration for complex app logic.
A JS library for predictable global state management
Simple, scalable state management.
Build forms in React, without the tears 😭
🤖 Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot