Transitions
事件和转换在 XState 状态机中定义在状态的 on 属性内。
事件与转换
当一个 actor 接收到事件时,其状态机会根据当前状态判断是否存在可用的转换。如果存在可用转换,状态机将执行该转换的动作(actions),并进入目标状态。
ts
import { createMachine } from 'xstate';
const feedbackMachine = createMachine({
id: 'feedback',
initial: 'question',
states: {
question: {
on: {
'feedback.good': {
target: 'thanks',
},
},
},
thanks: {},
},
});Event
Event 是一个对象,EventObject类型定义如下:
type:必须,字符串,事件ID- 其余字段:payload(载荷)
ts
actor.send({
type: 'feedback.update',
feedback: '很好',
rating: 5,
})Transition是确定的
每一个「状态 + 事件」的组合,都只会指向同一个确定的下一个状态。
在states中定义Transition
转换通过状态中的 on 属性定义:
ts
import { createMachine } from "xstate";
const feedbackMachine = createMachine({
id: "feedback",
initial: "question",
states: {
question: { on: { "feedback.good": { target: "thanks" } } },
thanks: {},
},
});Transition 执行顺序
最基本的 transition:在 question 状态下,收到 submit 事件 → 进入 thanks
ts
createMachine({
initial: 'question',
states: {
question: {
on: {
submit: { target: 'thanks' },
},
},
thanks: {},
},
})Transition 会做三件事
- 判断是否匹配 event
- 如果该状态存在匹配事件的转换:
- 若无 guard,直接生效
- 若 guard 返回
true,则生效
- 执行 actions
- 进入目标状态
Self Transition
根级自转换
特点:
- 没有
target - 状态不变
- 只改 context / 执行动作
ts
on: {
increment: {
// 没有 target
actions: assign({
count: ({ context }) => context.count + 1,
}),
},
}Transitions between states
ts
const machine = createMachine({
context: { count: 0 },
initial: "inactive",
states: {
inactive: { on: { activate: { target: "active" } } },
active: {
on: {
someEvent: {
actions: assign({ count: ({ context }) => context.count + 1 }),
},
},
},
},
});Parent to child transitions
特点:
transition 定义在父状态
target 指向子状态
当一个状态机 actor 接收到事件时,它会优先从最深层(原子状态)开始检查,看看是否存在可用的转换。如果没有,就向上回溯到父状态继续检查,依此类推,直到到达状态机的根状态。
例如,下面的状态机中,不管当前处于哪个状态,只要触发 mode.reset 事件,都会跳转到 colorMode.system 状态。
ts
const machine = createMachine({
id: "colorMode",
initial: "system",
states: {
system: {},
auto: {},
light: { on: { "mode.toggle": { target: "dark" } } },
dark: { on: { "mode.toggle": { target: "light" } } },
},
on: { "mode.reset": { target: ".system" } },
});初始状态:colorMode.system
父级on:
ts
on: { "mode.reset": { target: ".system" } },假设state.value==='dark',如果执行:
ts
send({type:'mode.reset'})因为dark状态中并不存在mode.reset事件,因此向上查找,在父节点中找到
target的三种定位方式
. 表示 “相对于当前状态节点(父节点)”,system 是该父节点下的子状态
Sibling descendent states(兄弟状态的后代)
{ target: 'sibling.child.grandchild' }父到后代
ts
{ target: '.child.grandchild' }到任意状态
通过 id 直接定位到状态机中的任意状态,# 表示 全局 id 引用
ts
{ target: '#specificState' }示例:
ts
createMachine({
id: 'app',
states: {
auth: {
states: {
loggedOut: {
id: 'logout'
}
}
},
home: {}
}
})ts
on: {
FORCE_LOGOUT: {
target: '#logout'
}
}禁用Transitions
禁止转换的两种写法:
- 直接声明一个空对象
ts
state: {
on: {
event1: {}
}
}- target设置为
undefined
ts
on: {
event1: { target: undefined }
}| 写法 | 含义 |
|---|---|
on: { EVENT: { target: 'x' } } | 正常转换 |
on: { EVENT: {} } | 禁止转换(拦截冒泡,向父级寻找) |
on: { EVENT: undefined } | 等同于没写 |
on: { EVENT: { target: undefined } } | 禁止转换(拦截冒泡,向父级寻找) |
