# Events
An event is what causes a state machine to transition from its current state to its next state. All state transitions in a state machine are due to these events; state cannot change unless some stimulus (the event) causes it to change.
An event is an object with a type
property, signifying what type of event it is:
const timerEvent = {
type: 'TIMER'
};
As shorthand, in XState, events that only have a type
can be represented just by their string type:
// equivalent to { type: 'TIMER' }
const timerEvent = 'TIMER';
Event objects can also have other properties, which represent data associated with the event:
const keyDownEvent = {
type: 'keydown',
key: 'Enter'
};
# Sending Events
As explained in the transitions guide, a transition defines what the next state will be given the current state and the event, defined on its on: { ... }
property. This can be observed by passing an event into the transition method:
import { Machine } from 'xstate';
const lightMachine = Machine({
/* ... */
});
const { initialState } = lightMachine;
let nextState = lightMachine.transition(initialState, 'TIMER'); // string event
console.log(nextState.value);
// => 'yellow'
nextState = lightMachine.transition(nextState, { type: 'TIMER' }); // event object
console.log(nextState.value);
// => 'red'
By specifying the event type on the type
property, many native events, such as DOM events, are compatible and can be used directly with XState:
import { Machine, interpret } from 'xstate';
const mouseMachine = Machine({
/* ... */
});
const mouseService = interpret(mouseMachine).start();
window.addEventListener('mousemove', event => {
// event can be sent directly to service
mouseService.send(event);
});
# Null Events
A null event is an event that has no type, and occurs immediately once a state is entered. In transitions, it is represented by an empty string (''
):
// contrived example
const skipMachine = Machine({
id: 'skip',
initial: 'one',
states: {
one: {
on: { CLICK: 'two' }
},
two: {
// null event '' always occurs once state is entered
// immediately take the transition to 'three'
on: { '': 'three' }
},
three: {
type: 'final'
}
}
});
const { initialState } = skipMachine;
const nextState = skipMachine.transition(initialState, 'CLICK');
console.log(nextState.value);
// => 'three'
There are many use cases for null events, especially when defining transient transitions, where a (potentially transient) state immediately determines what the next state should be based on conditions:
const isAdult = ({ age }) => age >= 18;
const isMinor = ({ age }) => age < 18;
const ageMachine = Machine({
id: 'age',
context: { age: undefined }, // age unknown
initial: 'unknown',
states: {
unknown: {
on: {
// immediately take transition that satisfies conditional guard.
// otherwise, no transition occurs
'': [
{ target: 'adult', cond: isAdult },
{ target: 'child', cond: isMinor }
]
}
},
adult: { type: 'final' },
child: { type: 'final' }
}
});
console.log(ageMachine.initialState.value);
// => 'unknown'
const personData = { age: 28 };
const personMachine = ageMachine.withContext(personData);
console.log(personMachine.initialState.value);
// => 'adult'
# SCXML
Events in SCXML contain information relevant to the source of the event, and have a different schema than event objects in XState. Internally, event objects are converted to SCXML events for compatibility.
SCXML events include:
name
- a character string giving the name of the event. This is equivalent to the.type
property of an XState event.type
- the event type:'platform'
,'external'
, or'internal'
.platform
events are raised by the platform itself, such as error events.internal
events are raised byraise(...)
actions or bysend(...)
actions withtarget: '_internal'
.external
events describe all other events.
sendid
- the send ID of the triggeringsend(...)
action.origin
- a string that allows the receiver of this event tosend(...)
a response event back to the origin.origintype
- used withorigin
invokeid
- the invoke ID of the invocation that triggered the child service.data
- any data that the sending entity chose to include with this event. This is equivalent to an XState event object.
The SCXML event form of all XState events is present in the _event
property of action and guard meta objects (third argument):
// ...
{
actions: {
someAction: (context, event, { _event }) => {
console.log(_event); // SCXML event
};
},
guards: {
someGuard: (context, event, { _event }) => {
console.log(_event); // SCXML event
}
}
}
// ..