Internal and external transitions
Transitions in statecharts can be one of two types: internal or external. External transitions are transitions that leave the machine’s current state node; the “source” state node on which the transition is defined.
In the example below, a -> FOO -> b
is an external transition.
import { createMachine } from 'xstate';
createMachine({
initial: 'a',
states: {
a: {
on: {
FOO: 'b',
},
},
b: {},
},
});
The transition leaves the a
state and goes to the b
state, making it an external transition.
Internal transitions do not leave the current state. For example, self-transitions are internal transitions:
import { createMachine } from 'xstate';
createMachine(
{
initial: 'a',
states: {
a: {
on: {
FOO: {
actions: 'sayHello',
},
},
},
},
},
{
actions: {
sayHello: () => {
console.log('Hello!');
},
},
},
);
The FOO
transition never leaves the a
state, which makes it an internal transition.
However, you can force an internal transition to become an external transition. For self-transitions, you can specify the target on the transition to force it to be an external transition:
import { createMachine } from 'xstate';
createMachine(
{
initial: 'a',
states: {
a: {
entry: ['logThatThisStateWasEntered'],
on: {
FOO: {
target: 'a',
actions: 'sayHello',
},
},
},
},
},
{
actions: {
sayHello: () => {
console.log('Hello!');
},
logThatThisStateWasEntered: () => {
console.log('A was entered!');
},
},
},
);
When target
is a
, the transition becomes external, which means the node is exited and re-entered and the entry and exit actions will be re-fired. You can use this trick to re-run delays, restart services and it is also useful in parent and child states.