# Counter
These XState v4 docs are no longer maintained
XState v5 is out now! Read more about XState v5 (opens new window) and check out the XState v5 docs (opens new window).
This counter app example demonstrates a counter that has a single 'active'
state and two possible events:
'INC'
- an intent to increment the current count by 1'DEC'
- an intent to decrement the current count by 1
The count
is stored in context
.
import { createMachine, interpret, assign } from 'xstate';
const increment = (context) => context.count + 1;
const decrement = (context) => context.count - 1;
const counterMachine = createMachine({
initial: 'active',
context: {
count: 0
},
states: {
active: {
on: {
INC: { actions: assign({ count: increment }) },
DEC: { actions: assign({ count: decrement }) }
}
}
}
});
const counterService = interpret(counterMachine)
.onTransition((state) => console.log(state.context.count))
.start();
// => 0
counterService.send({ type: 'INC' });
// => 1
counterService.send({ type: 'INC' });
// => 2
counterService.send({ type: 'DEC' });
// => 1
# Modeling Min and Max
With guards, we can model min and max by preventing transitions on the 'DEC'
and 'INC'
events on certain values, respectively:
// ...
const isNotMax = (context) => context.count < 10;
const isNotMin = (context) => context.count >= 0;
const counterMachine = createMachine({
initial: 'active',
context: {
count: 0
},
states: {
active: {
on: {
INC: {
actions: assign({ count: increment }),
cond: isNotMax
},
DEC: {
actions: assign({ count: decrement }),
cond: isNotMin
}
}
}
}
});
// ...
// assume context is { count: 9 }
counterService.send({ type: 'INC' });
// => 10
counterService.send({ type: 'INC' }); // no transition taken!
// => 10