Skip to content

@xstate/graph

@xstate/graph 包 包含用于 XState 状态机的图算法和工具。

快速开始

  1. 安装 xstate@xstate/graph:
npm install xstate @xstate/graph
  1. 导入图形工具。例如:
import { createMachine } from 'xstate';
import { getSimplePaths } from '@xstate/graph';

const machine = createMachine(/* ... */);
const paths = getSimplePaths(machine);

API

getShortestPaths(machine, options?)

参数

  • machine - 要遍历的 Machine
  • options (可选) - 自定义算法如何遍历状态机的 选项

返回从初始状态到每个其他状态的 最短路径 (Dijkstra 算法) 的映射对象,其中:

  • 是字符串化的状态
  • 是一个包含以下属性的对象:
    • state - 目标 State
    • path - 从初始状态到目标状态的最短路径

path 是一个段的数组,每个段是一个包含以下属性的对象:

  • state - 段的 State
  • weight - 路径的总 权重
    • 目前,从一个状态到另一个状态的每次转换的权重为 1。未来将可自定义。
  • event - 将 machine 从一个状态转换到路径中下一个状态的事件对象

每条路径都以初始状态开始。

整体对象结构如下:

{
"<SERIALIZED STATE>": {
"state": State { ... },
"path": [
{
"state": State { ... },
"event": { "type": "<event.type>", "<PROP>": "<event.PROP>" }
},
{
"state": State { ... },
"event": { "type": "<event.type>", "<PROP>": "<event.PROP>" }
},
...
]
},
...
}

示例

import { createMachine } from 'xstate';
import { getShortestPaths } from '@xstate/graph';

const feedbackMachine = createMachine({
id: 'feedback',
initial: 'question',
states: {
question: {
on: {
CLICK_GOOD: 'thanks',
CLICK_BAD: 'form',
CLOSE: 'closed',
ESC: 'closed',
},
},
form: {
on: {
SUBMIT: 'thanks',
CLOSE: 'closed',
ESC: 'closed',
},
},
thanks: {
on: {
CLOSE: 'closed',
ESC: 'closed',
},
},
closed: {
type: 'final',
},
},
});

const shortestPaths = getShortestPaths(feedbackMachine);

console.log(shortestPaths);
// => {
// '"question"': {
// state: State { value: 'question', context: undefined },
// weight: 0,
// path: []
// },
// '"thanks"': {
// state: State { value: 'thanks', context: undefined },
// weight: 1,
// path: [
// {
// state: State { value: 'question', context: undefined },
// event: { type: 'CLICK_GOOD' }
// }
// ]
// },
// '"form"': {
// state: State { value: 'form', context: undefined },
// weight: 1,
// path: [
// {
// state: State { value: 'question', context: undefined },
// event: { type: 'CLICK_BAD' }
// }
// ]
// },
// '"closed"': {
// state: State { value: 'closed', context: undefined },
// weight: 1,
// path: [
// {
// state: State { value: 'question', context: undefined },
// event: { type: 'CLOSE' }
// }
// ]
// }
// };

getSimplePaths(machine, options?)

参数

  • machine - 要遍历的 Machine
  • options (可选) - 自定义算法如何遍历状态机的 选项

返回 简单路径 的映射对象,其中:

  • 是字符串化的状态
  • 是一个包含以下属性的对象:
    • state - 目标 State
    • paths - 从初始状态到目标状态的路径数组

每个 path 是一个段的数组,每个段是一个包含以下属性的对象:

  • state - 段的 State
  • event - 将 machine 从一个状态转换到路径中下一个状态的事件对象

每条路径都以初始状态开始。

整体对象结构如下:

{
"<SERIALIZED STATE>": {
"state": State { ... },
"paths": [
[
{
"state": State { ... },
"event": { "type": "<event.type>", "<PROP>": "<event.PROP>" }
},
{
"state": State { ... },
"event": { "type": "<event.type>", "<PROP>": "<event.PROP>" }
},
...
],
...
]
},
...
}

示例

import { createMachine } from 'xstate';
import { getSimplePaths } from '@xstate/graph';

const feedbackMachine = createMachine({
id: 'feedback',
initial: 'question',
states: {
question: {
on: {
CLICK_GOOD: 'thanks',
CLICK_BAD: 'form',
CLOSE: 'closed',
ESC: 'closed',
},
},
form: {
on: {
SUBMIT: 'thanks',
CLOSE: 'closed',
ESC: 'closed',
},
},
thanks: {
on: {
CLOSE: 'closed',
ESC: 'closed',
},
},
closed: {
type: 'final',
},
},
});

const simplePaths = getSimplePaths(feedbackMachine);

console.log(simplePaths);
// => {
// '"question"': {
// state: { value: 'question', context: undefined },
// paths: [[]]
// },
// '"thanks"': {
// state: { value: 'thanks', context: undefined },
// paths: [
// [
// {
// state: { value: 'question', context: undefined },
// event: { type: 'CLICK_GOOD' }
// }
// ],
// [
// {
// state: { value: 'question', context: undefined },
// event: { type: 'CLICK_BAD' }
// },
// {
// state: { value: 'form', context: undefined },
// event: { type: 'SUBMIT' }
// }
// ]
// ]
// },
// '"closed"': {
// state: { value: 'closed', context: undefined },
// paths: [
// [
// {
// state: { value: 'question', context: undefined },
// event: { type: 'CLICK_GOOD' }
// },
// {
// state: { value: 'thanks', context: undefined },
// event: { type: 'CLOSE' }
// }
// ],
// [
// {
// state: { value: 'question', context: undefined },
// event: { type: 'CLICK_GOOD' }
// },
// {
// state: { value: 'thanks', context: undefined },
// event: { type: 'ESC' }
// }
// ],
// ...
// ]
// },
// ...
// };

getPathFromEvents(machine, events)

参数:

  • machine - 要遍历的 Machine
  • events - 生成路径的事件序列

返回一个包含以下键的路径对象:

  • state - 目标 State
  • segments - 一个对象数组,每个对象具有以下结构:
    • state - 段的 State
    • event - 将 machine 从该状态转换到路径中下一个状态的事件对象
import { createMachine } from 'xstate';
import { getSimplePaths } from '@xstate/graph';

const feedbackMachine = createMachine({
id: 'feedback',
initial: 'question',
states: {
question: {
on: {
CLICK_GOOD: 'thanks',
CLICK_BAD: 'form',
CLOSE: 'closed',
ESC: 'closed',
},
},
form: {
on: {
SUBMIT: 'thanks',
CLOSE: 'closed',
ESC: 'closed',
},
},
thanks: {
on: {
CLOSE: 'closed',
ESC: 'closed',
},
},
closed: {
type: 'final',
},
},
});

const path = getPathFromEvents(feedbackMachine, [
{ type: 'CLICK_GOOD' },
{ type: 'SUBMIT' },
{ type: 'CLOSE' },
]);

console.log(path);
// => {
// state: { value: 'closed' },
// segments: [
// {
// state: { value: 'question' },
// event: { type: 'CLICK_GOOD' },
// },
// {
// state: { value: 'form' },
// event: { type: 'SUBMIT' },
// },
// {
// state: { value: 'thanks' },
// event: { type: 'CLOSE' },
// },
// ],
// }

toDirectedGraph(machine)

machine 转换为有向图结构。

参数类型描述
machinecreateMachine(...) 创建的 XState 机器要转换为有向图结构的机器

示例

import { toDirectedGraph } from '@xstate/graph';

const machine = createMachine({/* ... */});

const digraph = toDirectedGraph(machine);

// 返回一个具有以下结构的对象:
{
id: '...',
stateNode: /* StateNode */,
children: [
{ id: '...', children: [/* ... */], edges: [/* ... */] },
{ id: '...', /* ... */ },
// ...
],
edges: [
{ source: /* ... */, target: /* ... */, transition: /* ... */ }
// ...
]
}

选项

可以将选项传递给 getShortestPathsgetSimplePaths 以自定义如何遍历由状态机表示的图:

  • events - 事件类型到事件对象数组的映射,用于这些事件
  • filter - 一个函数,用于确定是否应遍历 state。如果返回 false,遍历算法将假定状态已被“看到”并忽略对其的遍历。

示例

在下面的示例中,INC 事件被扩展为包含两个可能的事件,分别为 value: 1value: 2 作为负载。它还确保 state.context.count <= 5;否则,这个状态机将被无限遍历。

const counterMachine = createMachine({
id: 'counter',
initial: 'active',
context: { count: 0 },
states: {
active: {
on: {
INC: {
actions: assign({ count: (ctx, e) => ctx.count + e.value }),
},
},
},
},
});

const shortestPaths = getShortestPaths(counterMachine, {
events: {
INC: [
{ type: 'INC', value: 1 },
{ type: 'INC', value: 2 },
],
},
filter: (state) => state.context.count <= 5,
});

console.log(shortestPaths);
// => {
// '"active" | {"count":0}': {
// state: { value: 'active', context: { count: 0 } },
// weight: 0,
// path: []
// },
// '"active" | {"count":1}': {
// state: { value: 'active', context: { count: 1 } },
// weight: 1,
// path: [
// {
// state: { value: 'active', context: { count: 0 } },
// event: { type: 'INC', value: 1 }
// }
// ]
// },
// '"active" | {"count":2}': {
// state: { value: 'active', context: { count: 2 } },
// weight: 1,
// path: [
// {
// state: { value: 'active', context: { count: 0 } },
// event: { type: 'INC', value: 2 }
// }
// ]
// },
// '"active" | {"count":3}': {
// state: { value: 'active', context: { count: 3 } },
// weight: 2,
// path: [
// {
// state: { value: 'active', context: { count: 0 } },
// event: { type: 'INC', value: 1 }
// },
// {
// state: { value: 'active', context: { count: 1 } },
// event: { type: 'INC', value: 2 }
// }
// ]
// },
// ...
// };