Observables
Observables are streams of values emitted over time. They could be considered an array or collection whose values are emitted asynchronously instead of all at once. There are many implementations of observables in JavaScript; the most popular one is RxJS.
Observables can be invoked, sending events to the parent machine. An observable invocation is a function that takes context
and event
as arguments and returns an observable stream of events. The observable is unsubscribed when the state on which the observable is invoked is exited.
In the example below, the intervalMachine
will receive the events from interval(...)
mapped to event objects until the observable is “completed” when it’s done emitting values. If the CANCEL
event happens, the observable will be disposed of as .unsubscribe()
will be called internally.
import { createMachine, interpret } from 'xstate';
import { interval } from 'rxjs';
import { map, take } from 'rxjs/operators';
const intervalMachine = createMachine({
initial: 'counting',
context: { myInterval: 1000 },
states: {
counting: {
invoke: {
src: (context, event) =>
interval(context.myInterval).pipe(
map((value) => ({ type: 'COUNT', value })),
take(5)
),
onDone: 'finished',
},
on: {
COUNT: { actions: 'notifyCount' },
CANCEL: { target: 'finished' },
},
},
finished: {
type: 'final',
},
},
});
Hot observables​
You don’t necessarily need to create observables for every invocation. You could reference a “hot observable” instead:
import { fromEvent } from 'rxjs';
import { createMachine } from 'xstate';
const mouseMove$ = fromEvent(document.body, 'mousemove');
const mouseMachine = createMachine({
id: 'mouse',
// ...
invoke: {
src: (context, event) => mouseMove$,
},
on: {
mousemove: {
/* ... */
},
},
});