UNPKG

8.59 kBMarkdownView Raw
1<p align="center">
2 <a href="https://xstate.js.org">
3 <br />
4 <img src="https://i.imgur.com/FshbFOv.png" alt="XState" width="100"/>
5 <br />
6 <sub><strong>JavaScript state machines and statecharts</strong></sub>
7 <br />
8 <br />
9 </a>
10</p>
11
12[![npm version](https://badge.fury.io/js/xstate.svg)](https://badge.fury.io/js/xstate)
13[![Statecharts gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/statecharts/statecharts)
14<img src="https://opencollective.com/xstate/tiers/backer/badge.svg?label=sponsors&color=brightgreen" />
15
16JavaScript and TypeScript [finite state machines](https://en.wikipedia.org/wiki/Finite-state_machine) and [statecharts](https://www.sciencedirect.com/science/article/pii/0167642387900359/pdf) for the modern web.
17
18📖 [Read the documentation](https://xstate.js.org/docs)
19📑 Adheres to the [SCXML specification](https://www.w3.org/TR/scxml/).
20
21## Packages
22
23- 🤖 `xstate` - Core finite state machine and statecharts library + interpreter
24- [🔬 `@xstate/fsm`](https://github.com/statelyai/xstate/tree/main/packages/xstate-fsm) - Minimal finite state machine library
25- [📉 `@xstate/graph`](https://github.com/statelyai/xstate/tree/main/packages/xstate-graph) - Graph traversal utilities for XState
26- [⚛️ `@xstate/react`](https://github.com/statelyai/xstate/tree/main/packages/xstate-react) - React hooks and utilities for using XState in React applications
27- [✅ `@xstate/test`](https://github.com/statelyai/xstate/tree/main/packages/xstate-test) - Model-based testing utilities for XState
28
29## Super quick start
30
31```bash
32npm install xstate
33```
34
35```js
36import { createMachine, interpret } from 'xstate';
37
38// Stateless machine definition
39// machine.transition(...) is a pure function used by the interpreter.
40const toggleMachine = createMachine({
41 id: 'toggle',
42 initial: 'inactive',
43 states: {
44 inactive: { on: { TOGGLE: 'active' } },
45 active: { on: { TOGGLE: 'inactive' } }
46 }
47});
48
49// Machine instance with internal state
50const toggleService = interpret(toggleMachine)
51 .onTransition((state) => console.log(state.value))
52 .start();
53// => 'inactive'
54
55toggleService.send('TOGGLE');
56// => 'active'
57
58toggleService.send('TOGGLE');
59// => 'inactive'
60```
61
62- [Visualizer](#visualizer)
63- [Why? (info about statecharts)](#why)
64- [Installation](https://xstate.js.org/docs/guides/installation.html)
65- [Finite State Machines](#finite-state-machines)
66- [Hierarchical (Nested) State Machines](#hierarchical--nested--state-machines)
67- [Parallel State Machines](#parallel-state-machines)
68- [History States](#history-states)
69
70## Visualizer
71
72**[Visualize, simulate, and share your statecharts in XState Viz!](https://stately.ai/viz)**
73
74<a href="https://stately.ai/viz" title="xstate visualizer"><img src="https://i.imgur.com/3pEB0B3.png" alt="xstate visualizer" width="300" /></a>
75
76## Why?
77
78Statecharts 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.
79
80Read [📽 the slides](http://slides.com/davidkhourshid/finite-state-machines) ([🎥 video](https://www.youtube.com/watch?v=VU1NKX6Qkxc)) or check out these resources for learning about the importance of finite state machines and statecharts in user interfaces:
81
82- [Statecharts - A Visual Formalism for Complex Systems](https://www.sciencedirect.com/science/article/pii/0167642387900359/pdf) by David Harel
83- [The World of Statecharts](https://statecharts.github.io/) by Erik Mogensen
84- [Pure UI](https://rauchg.com/2015/pure-ui) by Guillermo Rauch
85- [Pure UI Control](https://medium.com/@asolove/pure-ui-control-ac8d1be97a8d) by Adam Solove
86- [Stately Discord](https://discord.gg/xstate) chat about anything related to statecharts and XState
87- [GitHub Discussions](https://github.com/statelyai/xstate/discussions)
88
89## Finite State Machines
90
91<img src="https://imgur.com/rqqmkJh.png" alt="Light Machine" width="300" />
92
93```js
94import { createMachine } from 'xstate';
95
96const lightMachine = createMachine({
97 id: 'light',
98 initial: 'green',
99 states: {
100 green: {
101 on: {
102 TIMER: 'yellow'
103 }
104 },
105 yellow: {
106 on: {
107 TIMER: 'red'
108 }
109 },
110 red: {
111 on: {
112 TIMER: 'green'
113 }
114 }
115 }
116});
117
118const currentState = 'green';
119
120const nextState = lightMachine.transition(currentState, 'TIMER').value;
121
122// => 'yellow'
123```
124
125## Hierarchical (Nested) State Machines
126
127<img src="https://imgur.com/GDZAeB9.png" alt="Hierarchical Light Machine" width="300" />
128
129```js
130import { createMachine } from 'xstate';
131
132const pedestrianStates = {
133 initial: 'walk',
134 states: {
135 walk: {
136 on: {
137 PED_TIMER: 'wait'
138 }
139 },
140 wait: {
141 on: {
142 PED_TIMER: 'stop'
143 }
144 },
145 stop: {}
146 }
147};
148
149const lightMachine = createMachine({
150 id: 'light',
151 initial: 'green',
152 states: {
153 green: {
154 on: {
155 TIMER: 'yellow'
156 }
157 },
158 yellow: {
159 on: {
160 TIMER: 'red'
161 }
162 },
163 red: {
164 on: {
165 TIMER: 'green'
166 },
167 ...pedestrianStates
168 }
169 }
170});
171
172const currentState = 'yellow';
173
174const nextState = lightMachine.transition(currentState, 'TIMER').value;
175// => {
176// red: 'walk'
177// }
178
179lightMachine.transition('red.walk', 'PED_TIMER').value;
180// => {
181// red: 'wait'
182// }
183```
184
185**Object notation for hierarchical states:**
186
187```js
188// ...
189const waitState = lightMachine.transition({ red: 'walk' }, 'PED_TIMER').value;
190
191// => { red: 'wait' }
192
193lightMachine.transition(waitState, 'PED_TIMER').value;
194
195// => { red: 'stop' }
196
197lightMachine.transition({ red: 'stop' }, 'TIMER').value;
198
199// => 'green'
200```
201
202## Parallel State Machines
203
204<img src="https://imgur.com/GKd4HwR.png" width="300" alt="Parallel state machine" />
205
206```js
207const wordMachine = createMachine({
208 id: 'word',
209 type: 'parallel',
210 states: {
211 bold: {
212 initial: 'off',
213 states: {
214 on: {
215 on: { TOGGLE_BOLD: 'off' }
216 },
217 off: {
218 on: { TOGGLE_BOLD: 'on' }
219 }
220 }
221 },
222 underline: {
223 initial: 'off',
224 states: {
225 on: {
226 on: { TOGGLE_UNDERLINE: 'off' }
227 },
228 off: {
229 on: { TOGGLE_UNDERLINE: 'on' }
230 }
231 }
232 },
233 italics: {
234 initial: 'off',
235 states: {
236 on: {
237 on: { TOGGLE_ITALICS: 'off' }
238 },
239 off: {
240 on: { TOGGLE_ITALICS: 'on' }
241 }
242 }
243 },
244 list: {
245 initial: 'none',
246 states: {
247 none: {
248 on: { BULLETS: 'bullets', NUMBERS: 'numbers' }
249 },
250 bullets: {
251 on: { NONE: 'none', NUMBERS: 'numbers' }
252 },
253 numbers: {
254 on: { BULLETS: 'bullets', NONE: 'none' }
255 }
256 }
257 }
258 }
259});
260
261const boldState = wordMachine.transition('bold.off', 'TOGGLE_BOLD').value;
262
263// {
264// bold: 'on',
265// italics: 'off',
266// underline: 'off',
267// list: 'none'
268// }
269
270const nextState = wordMachine.transition(
271 {
272 bold: 'off',
273 italics: 'off',
274 underline: 'on',
275 list: 'bullets'
276 },
277 'TOGGLE_ITALICS'
278).value;
279
280// {
281// bold: 'off',
282// italics: 'on',
283// underline: 'on',
284// list: 'bullets'
285// }
286```
287
288## History States
289
290<img src="https://imgur.com/I4QsQsz.png" width="300" alt="Machine with history state" />
291
292```js
293const paymentMachine = createMachine({
294 id: 'payment',
295 initial: 'method',
296 states: {
297 method: {
298 initial: 'cash',
299 states: {
300 cash: { on: { SWITCH_CHECK: 'check' } },
301 check: { on: { SWITCH_CASH: 'cash' } },
302 hist: { type: 'history' }
303 },
304 on: { NEXT: 'review' }
305 },
306 review: {
307 on: { PREVIOUS: 'method.hist' }
308 }
309 }
310});
311
312const checkState = paymentMachine.transition('method.cash', 'SWITCH_CHECK');
313
314// => State {
315// value: { method: 'check' },
316// history: State { ... }
317// }
318
319const reviewState = paymentMachine.transition(checkState, 'NEXT');
320
321// => State {
322// value: 'review',
323// history: State { ... }
324// }
325
326const previousState = paymentMachine.transition(reviewState, 'PREVIOUS').value;
327
328// => { method: 'check' }
329```
330
331## Sponsors
332
333Huge thanks to the following companies for sponsoring `xstate`. You can sponsor further `xstate` development [on OpenCollective](https://opencollective.com/xstate).
334
335<a href="https://tipe.io" title="Tipe.io"><img src="https://cdn.tipe.io/tipe/tipe-logo.svg?w=240" style="background:#613DEF" /></a>
336<a href="https://webflow.com" title="Webflow"><img src="https://uploads-ssl.webflow.com/583347ca8f6c7ee058111b3b/5b03bde0971fdd75d75b5591_webflow.png" height="100" /></a>