Delayed (after) transitions
Delayed transitions are transitions that only happen after a set amount of time. Delayed transitions are handy for building timeouts and intervals into your application logic. If another event occurs before the end of the timer, the transition doesn’t complete.
Delayed transitions are defined on the after
property in milliseconds. They are often referred to as “after” transitions.
import { createMachine } from 'xstate';
const pushTheButtonGame = createMachine({
initial: 'waitingForButtonPush',
states: {
waitingForButtonPush: {
after: {
5000: {
target: 'timedOut',
actions: 'logThatYouGotTimedOut',
},
},
on: {
PUSH_BUTTON: {
actions: 'logSuccess',
target: 'success',
},
},
},
success: {},
timedOut: {},
},
});
↓Jump to learning more about delays in XState↓
View this machine in Stately Studio.
In a video player, want the video to be Closed out of fullscreen mode a few seconds after the video has Stopped, instead of closing the fullscreen mode suddenly as soon as the video is stopped. The eventless transition above transitions from the Stopped state to the Closed state after 5 seconds.
Using delayed transitions in Stately Studio
In Stately Studio, delayed transitions are labeled “after.”
Make an event into a delayed transition
Delayed transitions have a default time interval of 500ms (0.5 seconds).
On the canvas
- Select the event you want to replace with a delayed transition.
- Right-click the event to open the edit menu.
- From the Event type options, choose After to turn the event into a delayed transition.
Using the transition Details panel
- Open the transition Details panel from the right tool menu.
- From the Event type dropdown menu, choose After to turn the event into a delayed transition.
Specify delay time
Your delay time interval will be displayed in a human-readable format on hover. For example, 15000ms will be displayed as 15 seconds.
- Select the delayed transition.
- Open the transition Details panel from the right tool menu.
- Use the Delay text input to specify the interval in milliseconds.
Delays
You can define delays in a few ways: inlined, referenced, and as an expression.
Inlined delays
You can define an inlined delay by specifying the delay time (in milliseconds) directly:
const machine = createMachine({
initial: 'idle',
states: {
idle: {
after: {
1000: { target: 'nextState' },
},
},
nextState: {},
},
});
This will transition to the nextState
state after 1000ms.
Referenced delays
You can also define referenced delays by specifying a string delay key, and providing the actual delay time separately.
For example:
const machine = createMachine(
{
initial: 'idle',
states: {
idle: {
after: {
timeout: { target: 'nextState' },
},
},
nextState: {},
},
},
{
delays: {
timeout: 1000,
},
},
);
Delay expressions
The delay option can be evaluated as a delay expression. The delay expression function takes in an object that contains context
and event
properties and returns the resolved delay
(in milliseconds).
`after: [{ delay: () => 1000, target: ... }]`;
Lifecycle
Delayed transition timers are canceled when the state is exited.
Testing
- Simulated clock
TypeScript
You can strongly type the delays
of your machine in the types.delays
property of the machine config.
const machine = createMachine({
types: {} as {
delays: 'shortTimeout' | 'longTimeout' | 'eventually';
// ...
},
// ...
after: {
// Autocompleted
shortTimeout: {
/* ... */
},
},
on: {
someEvent: {
actions: raise(
{ type: 'anotherEvent' },
{
// Autocompleted
delay: 'eventually',
},
),
},
},
});
Cheatsheet
Use our XState delayed transitions cheatsheet below to get started quickly.
createMachine({
after: {
DELAY: {
/* ... */
},
},
}).provide({
delays: {
DELAY: 1000, // or expression
},
});