UNPKG

8.61 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- [Spectrum - Statecharts Community](https://spectrum.chat/statecharts) (For XState specific questions, please use the [GitHub Discussions](https://github.com/statelyai/xstate/discussions))
87
88## Finite State Machines
89
90<img src="https://imgur.com/rqqmkJh.png" alt="Light Machine" width="300" />
91
92```js
93import { createMachine } from 'xstate';
94
95const lightMachine = createMachine({
96 id: 'light',
97 initial: 'green',
98 states: {
99 green: {
100 on: {
101 TIMER: 'yellow'
102 }
103 },
104 yellow: {
105 on: {
106 TIMER: 'red'
107 }
108 },
109 red: {
110 on: {
111 TIMER: 'green'
112 }
113 }
114 }
115});
116
117const currentState = 'green';
118
119const nextState = lightMachine.transition(currentState, 'TIMER').value;
120
121// => 'yellow'
122```
123
124## Hierarchical (Nested) State Machines
125
126<img src="https://imgur.com/GDZAeB9.png" alt="Hierarchical Light Machine" width="300" />
127
128```js
129import { createMachine } from 'xstate';
130
131const pedestrianStates = {
132 initial: 'walk',
133 states: {
134 walk: {
135 on: {
136 PED_TIMER: 'wait'
137 }
138 },
139 wait: {
140 on: {
141 PED_TIMER: 'stop'
142 }
143 },
144 stop: {}
145 }
146};
147
148const lightMachine = createMachine({
149 id: 'light',
150 initial: 'green',
151 states: {
152 green: {
153 on: {
154 TIMER: 'yellow'
155 }
156 },
157 yellow: {
158 on: {
159 TIMER: 'red'
160 }
161 },
162 red: {
163 on: {
164 TIMER: 'green'
165 },
166 ...pedestrianStates
167 }
168 }
169});
170
171const currentState = 'yellow';
172
173const nextState = lightMachine.transition(currentState, 'TIMER').value;
174// => {
175// red: 'walk'
176// }
177
178lightMachine.transition('red.walk', 'PED_TIMER').value;
179// => {
180// red: 'wait'
181// }
182```
183
184**Object notation for hierarchical states:**
185
186```js
187// ...
188const waitState = lightMachine.transition({ red: 'walk' }, 'PED_TIMER').value;
189
190// => { red: 'wait' }
191
192lightMachine.transition(waitState, 'PED_TIMER').value;
193
194// => { red: 'stop' }
195
196lightMachine.transition({ red: 'stop' }, 'TIMER').value;
197
198// => 'green'
199```
200
201## Parallel State Machines
202
203<img src="https://imgur.com/GKd4HwR.png" width="300" alt="Parallel state machine" />
204
205```js
206const wordMachine = createMachine({
207 id: 'word',
208 type: 'parallel',
209 states: {
210 bold: {
211 initial: 'off',
212 states: {
213 on: {
214 on: { TOGGLE_BOLD: 'off' }
215 },
216 off: {
217 on: { TOGGLE_BOLD: 'on' }
218 }
219 }
220 },
221 underline: {
222 initial: 'off',
223 states: {
224 on: {
225 on: { TOGGLE_UNDERLINE: 'off' }
226 },
227 off: {
228 on: { TOGGLE_UNDERLINE: 'on' }
229 }
230 }
231 },
232 italics: {
233 initial: 'off',
234 states: {
235 on: {
236 on: { TOGGLE_ITALICS: 'off' }
237 },
238 off: {
239 on: { TOGGLE_ITALICS: 'on' }
240 }
241 }
242 },
243 list: {
244 initial: 'none',
245 states: {
246 none: {
247 on: { BULLETS: 'bullets', NUMBERS: 'numbers' }
248 },
249 bullets: {
250 on: { NONE: 'none', NUMBERS: 'numbers' }
251 },
252 numbers: {
253 on: { BULLETS: 'bullets', NONE: 'none' }
254 }
255 }
256 }
257 }
258});
259
260const boldState = wordMachine.transition('bold.off', 'TOGGLE_BOLD').value;
261
262// {
263// bold: 'on',
264// italics: 'off',
265// underline: 'off',
266// list: 'none'
267// }
268
269const nextState = wordMachine.transition(
270 {
271 bold: 'off',
272 italics: 'off',
273 underline: 'on',
274 list: 'bullets'
275 },
276 'TOGGLE_ITALICS'
277).value;
278
279// {
280// bold: 'off',
281// italics: 'on',
282// underline: 'on',
283// list: 'bullets'
284// }
285```
286
287## History States
288
289<img src="https://imgur.com/I4QsQsz.png" width="300" alt="Machine with history state" />
290
291```js
292const paymentMachine = createMachine({
293 id: 'payment',
294 initial: 'method',
295 states: {
296 method: {
297 initial: 'cash',
298 states: {
299 cash: { on: { SWITCH_CHECK: 'check' } },
300 check: { on: { SWITCH_CASH: 'cash' } },
301 hist: { type: 'history' }
302 },
303 on: { NEXT: 'review' }
304 },
305 review: {
306 on: { PREVIOUS: 'method.hist' }
307 }
308 }
309});
310
311const checkState = paymentMachine.transition('method.cash', 'SWITCH_CHECK');
312
313// => State {
314// value: { method: 'check' },
315// history: State { ... }
316// }
317
318const reviewState = paymentMachine.transition(checkState, 'NEXT');
319
320// => State {
321// value: 'review',
322// history: State { ... }
323// }
324
325const previousState = paymentMachine.transition(reviewState, 'PREVIOUS').value;
326
327// => { method: 'check' }
328```
329
330## Sponsors
331
332Huge thanks to the following companies for sponsoring `xstate`. You can sponsor further `xstate` development [on OpenCollective](https://opencollective.com/xstate).
333
334<a href="https://tipe.io" title="Tipe.io"><img src="https://cdn.tipe.io/tipe/tipe-logo.svg?w=240" style="background:#613DEF" /></a>
335<a href="https://webflow.com" title="Webflow"><img src="https://uploads-ssl.webflow.com/583347ca8f6c7ee058111b3b/5b03bde0971fdd75d75b5591_webflow.png" height="100" /></a>