# 状态机 Machines

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

# 配置

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

import { createMachine } from 'xstate';

const lightMachine = createMachine({
  // 状态机标识
  id: 'light',

  // 初始状态
  initial: 'green',

  // 整个状态机的本地 context
  context: {
    elapsed: 0,
    direction: 'east'
  },

  // 状态定义
  states: {
    green: {
      /* ... */
    },
    yellow: {
      /* ... */
    },
    red: {
      /* ... */
    }
  }
});

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

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

# 选项

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

const lightMachine = createMachine(
  {
    id: 'light',
    initial: 'green',
    states: {
      green: {
        // 通过字符串引用 action
        entry: 'alertGreen'
      }
    }
  },
  {
    actions: {
      // action 执行
      alertGreen: (context, event) => {
        alert('Green!');
      }
    },
    activities: {
      /* ... */
    },
    delays: {
      /* ... */
    },
    guards: {
      /* ... */
    },
    services: {
      /* ... */
    }
  }
);

该对象有 5 个可选属性:

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

# 扩展状态机

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

const lightMachine = // (同上面的例子一样)

const noAlertLightMachine = lightMachine.withConfig({
  actions: {
    alertGreen: (context, event) => {
      console.log('green');
    }
  }
});

# 初始化 Context

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

const lightMachine = // (像第一个例子)

const testLightMachine = lightMachine.withContext({
  elapsed: 1000,
  direction: 'north'
});

注意

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

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