在状态图中,并行状态(Parallel states)是具有多个子状态(也称为域)的状态,这些子状态同时处于活动状态。这与父状态(parent state)不同,父状态一次只有一个子状态处于活动状态。
并行状态具有以下特征:
- 进入并行状态也将同时进入其所有域。
- 退出并行状态也将同时退出其所有域。
- 以并行状态接收的事件会被所有域同时接收和处理。
下面是一个音乐播放器示例,其并行状态由两个域组成,一个用于处理播放播放进度,另一个用于处理音量:
import { createMachine, assign } from 'xstate';
const playerMachine = createMachine({
id: '播放器',
type: 'parallel',
states: {
track: {
initial: '暂停中',
states: {
paused: {
on: { PLAY: '播放中' },
},
playing: {
on: { STOP: '暂停中' },
},
},
},
volume: {
initial: '正常音量',
states: {
normal: {
on: { MUTE: '静音' },
},
muted: {
on: { UNMUTE: '正常音量' },
},
},
},
},
});
上述代码将构造如下图的状态机,在Stately中查看
并行状态的值
并行状态的值是一个对象,具有其每个域的状态值。
使用下列代码打印上述音乐播放器的状态值,在打印的值中可以看到其中包含了两个子状态:进度track和音量volume的值。
const playerActor = createActor(playerMachine);
playerActor.start();
console.log(playerActor.getSnapshot().value);
// logs the object:
// {
// track: '暂停中',
// volume: '正常音量'
// }
并行的onDone转变
当并行状态的所有域都达到其最终状态时,将自动进行并行状态 onDone 的转变。
以下代码构造了一个煮咖啡的状态机。
import { createMachine } from "xstate";
export const machine = createMachine({
id: "煮咖啡",
initial: "preparing",
states: {
preparing: {
states: {
grindBeans: {
initial: "磨豆子中",
states: {
grindingBeans: {
on: {
BEANS_GROUND: {
target: "磨好了",
},
},
},
beansGround: {
type: "final",
},
},
},
boilWater: {
initial: "烧开水中",
states: {
boilingWater: {
on: {
WATER_BOILED: {
target: "烧开了",
},
},
},
waterBoiled: {
type: "final",
},
},
},
},
type: "parallel",
onDone: {
target: "开始制作咖啡",
},
},
makingCoffee: {},
},
});
在下列的煮咖啡状态机中,当两个域都达到其最终状态时,即磨豆子域到达磨豆子.磨好了状态并且烧开水域到达烧开水.水烧开了状态时,上层状态将自动进行 onDone 的转变,进入开始制作咖啡状态。
状态机如下图所示,在Stately中查看
建模思路(待补充)
- 避免在域之间进行状态转变
- 用于分离可能相互影响的关注点(例如:同步)
小结
创建并行状态的模板
import { createMachine } from "xstate";
const machine = createMachine({
// ...
states: {
type: 'parallel',
states: {
one: {/* ... */},
two: {/* ... */},
three: {/* ... */}
},
onDone: {
// 在所有域都到达最终状态时会自动进行onDone转换
}
}
});