Invoked actor
基本概念
invoke actor 是状态机在某个状态下“托管的一个外部执行单元”用来做 异步、并发、可取消、可通信 的事情。
状态机可以在某个状态中“调用”一个或多个 actor。当状态进入时,被调用的 actor 将开始运行,并在状态退出时停止。任何 XState actor 都可以被调用,包括简单的基于 Promise 的 actor,甚至是复杂的基于状态机的 actor。
ts
loading: {
invoke: {
id: 'getUser',
src: 'fetchUser',
input: ({ context: { userId } }) => ({ userId }),
onDone: {
target: 'success',
actions: assign({ user: ({ event }) => event.output }),
},
onError: {
target: 'failure',
actions: assign({ error: ({ event }) => event.error }),
},
},
},当状态机进入loading状态时:
- 创建并启动一个 actor 实例:
fetchUser - 当离开这个 state 时,自动停止 / 取消 这个 actor
- 如果在fetchUser执行期间,进行了状态的切换则:
- 不会触发
onDone - 不会触发
onError - 不会更新 context
- 不会再产生任何状态变化
- 不会触发
ts
import { setup, createActor, fromPromise, assign } from 'xstate';
const fetchUser = (userId: string) =>
fetch(`https://example.com/${userId}`).then((response) => response.text());
const userMachine = setup({
types: {
context: {} as {
userId: string;
user: object | undefined;
error: unknown;
},
},
actors: {
fetchUser: fromPromise(async ({ input }: { input: { userId: string } }) => {
const user = await fetchUser(input.userId);
return user;
}),
},
}).createMachine({
id: 'user',
initial: 'idle',
context: {
userId: '42',
user: undefined,
error: undefined,
},
states: {
idle: {
on: {
FETCH: { target: 'loading' },
},
},
loading: {
invoke: {
id: 'getUser',
src: 'fetchUser',
input: ({ context: { userId } }) => ({ userId }),
onDone: {
target: 'success',
actions: assign({ user: ({ event }) => event.output }),
},
onError: {
target: 'failure',
actions: assign({ error: ({ event }) => event.error }),
},
},
},
success: {},
failure: {
on: {
RETRY: { target: 'loading' },
},
},
},
});Invoked actor和Actions有什么不同
Actions 是“触发就不管了”
同步执行
不会被 await
不影响状态迁移
不能直接参与错误处理
ts
actions: async () => {
await fetch('/api'); // ❌ 这个 await 对状态机没意义
}states transition synchronously
状态迁移是原子、同步的
不存在“迁移中”这种中间态
你永远可以假设: 发送事件 → 立刻进入新状态
ts
invoke: {
src: 'fetchUser',
onError: {
target: 'failure',
actions: assign({ error: ({ event }) => event.error })
}
}
一个调用在状态节点的配置中通过 invoke 属性定义,其值是一个包含以下内容的对象:
src
在创建 actor 时要调用的 actor 逻辑 的来源,或指向机器中 提供实现 中定义的 actor 逻辑的字符串。
- Object
ts
invoke: {
src: someMachine,
}- String
ts
invoke: {
src: 'fetchUser',
}ts
createMachine(
{},
{
actors: {
fetchUser: fetchUserMachine,
},
}
);ts
invoke: {
id: 'fetchUser',
src: fetchUserMachine,
}Invoked Actor Object
src
ts
src:ActorLogic|string- string:actors中声明的引用名
ts
createMachine({}, {
actors: {
fetchUser: fetchUserMachine,
},
});id
用于标识创建的invoked actor实例的名称,在其父机器中是唯一的。
XState 为「某个 actor 完成」自动生成的事件类型名就会用到id:
ts
xstate.done.actor. + invoke 的 id这个事件通常是由父机器自动调用的,我们无需关心其内部具体的名字。
如果我们没有写id,xstate会为我们自动生成不可预测的id
input
传递给Actor的输入
onDone
Actor完成时触发
ts
onDone(({context,event})=>{...})- context:外部状态机的context
- event:父机器发送的事件
当 fetchUser 这个 actor 完成时,XState 自动发送 一个事件给父状态机:
{
type: 'xstate.done.actor.getUser',
output: <Promise resolve 的值>
}onError
Actor抛出错误时调用
onSnapshot
快照发生变化时触发
systemId
一个字符串,用于标识Actor,系统范围内唯一。
复用Invoked Actor
Invoked Actor Object
Array<Invoked Actor Object>
ts
const vitalsWorkflow = createMachine({
states: {
CheckVitals: {
invoke: [
{ src: 'checkTirePressure' },
{ src: 'checkOilPressure' },
{ src: 'checkCoolantLevel' },
{ src: 'checkBattery' },
],
},
},
});Invoked Actor
onDone
Actor完成时触发。Actor执行完成,会有一个output。可以通过event.output获取
ts
invoke: {
src: 'fetchForm',
onDone: [
{
target: 'step1',
guard: ({ event }) => (event.output as FormDTO).step === 'step1',
actions: 'restoreForm',
},
{
target: 'step2',
guard: ({ event }) => (event.output as FormDTO).step === 'step2',
actions: 'restoreForm',
},
{
target: 'review',
guard: ({ event }) => (event.output as FormDTO).step === 'review',
actions: 'restoreForm',
},
{
target: 'step1',
actions: 'restoreForm',
},
],
onError: {
// 如果加载失败,从第一步开始
target: 'step1',
},
},