状态机 Machines

状态机是一组有限的状态,可以根据事件确定性地相互转换。 要了解更多信息,请阅读 介绍状态图

配置

状态机和状态图都是使用 createMachine() 工厂函数定义的:

  1. import { createMachine } from 'xstate';
  2. const lightMachine = createMachine({
  3. // 状态机标识
  4. id: 'light',
  5. // 初始状态
  6. initial: 'green',
  7. // 整个状态机的本地 context
  8. context: {
  9. elapsed: 0,
  10. direction: 'east'
  11. },
  12. // 状态定义
  13. states: {
  14. green: {
  15. /* ... */
  16. },
  17. yellow: {
  18. /* ... */
  19. },
  20. red: {
  21. /* ... */
  22. }
  23. }
  24. });

状态机配置与 状态节点配置 相同,增加了上下文(context)属性:

代表状态机所有嵌套状态的本地“扩展状态”。 有关更多详细信息,请参阅文档 context 文档

选项

actionsactivitiesdelaysguards、 和 services 的实现可以在状态机配置中作为字符串引用,然后在 createMachine() 的第二个参数中指定为对象:

  1. const lightMachine = createMachine(
  2. {
  3. id: 'light',
  4. initial: 'green',
  5. states: {
  6. green: {
  7. // 通过字符串引用 action
  8. entry: 'alertGreen'
  9. }
  10. }
  11. },
  12. {
  13. actions: {
  14. // action 执行
  15. alertGreen: (context, event) => {
  16. alert('Green!');
  17. }
  18. },
  19. activities: {
  20. /* ... */
  21. },
  22. delays: {
  23. /* ... */
  24. },
  25. guards: {
  26. /* ... */
  27. },
  28. services: {
  29. /* ... */
  30. }
  31. }
  32. );

该对象有 5 个可选属性:

  • actions - action 名称到它们的执行的映射
  • activities - activities 名称与其执行的映射
  • delays - delays 名称与其执行的映射
  • guards - 转换守卫 (cond) ,名称与其执行的映射
  • services - 调用的服务 (src) ,名称与其执行的映射

扩展状态机

可以使用 .withConfig() 扩展现有状态机,它采用与上述相同的对象结构:

  1. const lightMachine = // (同上面的例子一样)
  2. const noAlertLightMachine = lightMachine.withConfig({
  3. actions: {
  4. alertGreen: (context, event) => {
  5. console.log('green');
  6. }
  7. }
  8. });

初始化 Context

如第一个示例所示,context 直接在配置本身中定义。 如果要使用不同的初始 context 扩展现有状态机,可以使用 .withContext() 并传入自定义 context

  1. const lightMachine = // (像第一个例子)
  2. const testLightMachine = lightMachine.withContext({
  3. elapsed: 1000,
  4. direction: 'north'
  5. });

::: warning 这 不会 对原始 context 进行浅层合并,而是将原始 context 替换为 .withContext(...)context。 你仍然可以通过引用 machine.context 手动“合并”上下文:

  1. const testLightMachine = lightMachine.withContext({
  2. // 合并原始 context
  3. ...lightMachine.context,
  4. elapsed: 1000
  5. });

:::