计数器

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.

  1. import { createMachine, interpret, assign } from 'xstate';
  2. const increment = (context) => context.count + 1;
  3. const decrement = (context) => context.count - 1;
  4. const counterMachine = createMachine({
  5. initial: 'active',
  6. context: {
  7. count: 0
  8. },
  9. states: {
  10. active: {
  11. on: {
  12. INC: { actions: assign({ count: increment }) },
  13. DEC: { actions: assign({ count: decrement }) }
  14. }
  15. }
  16. }
  17. });
  18. const counterService = interpret(counterMachine)
  19. .onTransition((state) => console.log(state.context.count))
  20. .start();
  21. // => 0
  22. counterService.send('INC');
  23. // => 1
  24. counterService.send('INC');
  25. // => 2
  26. counterService.send('DEC');
  27. // => 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:

  1. // ...
  2. const isNotMax = (context) => context.count < 10;
  3. const isNotMin = (context) => context.count >= 0;
  4. const counterMachine = createMachine({
  5. initial: 'active',
  6. context: {
  7. count: 0
  8. },
  9. states: {
  10. active: {
  11. on: {
  12. INC: {
  13. actions: assign({ count: increment }),
  14. cond: isNotMax
  15. },
  16. DEC: {
  17. actions: assign({ count: decrement }),
  18. cond: isNotMin
  19. }
  20. }
  21. }
  22. }
  23. });
  24. // ...
  25. // assume context is { count: 9 }
  26. counterService.send('INC');
  27. // => 10
  28. counterService.send('INC'); // no transition taken!
  29. // => 10