状态机
状态机 是描述某物行为的模型,例如一个 actor。有限状态 机描述了当一个 事件 发生时,actor 的状态如何转换到另一个状态。
状态机的好处
状态机有助于构建可靠和健壮的软件。阅读更多关于状态机的好处。
创建一个状态机
在 XState 中,状态机(称为“机器”)是使用 createMachine(config)
函数创建的:
import { createMachine } from 'xstate';
const feedbackMachine = createMachine({
id: 'feedback',
initial: 'question',
states: {
question: {
on: {
'feedback.good': {
target: 'thanks',
},
},
},
thanks: {
// ...
},
// ...
},
});
在这个例子中,机器有两个状态:question
和 thanks
。当 feedback.good
事件发送到机器时,question
状态会转换到 thanks
状态:
const feedbackActor = createActor(feedbackMachine);
feedbackActor.subscribe((state) => {
console.log(state.value);
});
feedbackActor.start();
// logs 'question'
feedbackActor.send({ type: 'feedback.good' });
// logs 'thanks'
从机器创建 actor
机器包含 actor 的逻辑。actor 是机器的运行实例;换句话说,它是由机器描述其逻辑的实体。可以从同一个机器创建多个 actor,每个 actor 都会表现出相同的行为(对接收到的事件的反应),但它们彼此独立并拥有自己的状态。
要创建 actor,请使用 createActor(machine)
函数:
import { createActor } from 'xstate';
const feedbackActor = createActor(feedbackMachine);
feedbackActor.subscribe((state) => {
console.log(state.value);
});
feedbackActor.start();
// logs 'question'
你还可以从其他类型的逻辑创建 actor,例如函数、promise 和 observable。
提供实现
机器实现是与状态机逻辑(状态和转换)无直接关系的语言特定代码。这包括:
可以在创建机器时通过 setup({...})
函数提供默认实现,然后可以使用 JSON 可序列化的字符串和/或对象(例如 { type: 'doSomething' }
)引用这些实现。
import { setup } from 'xstate';
const feedbackMachine = setup({
// 默认实现
actions: {
doSomething: () => {
console.log('Doing something!');
},
},
actors: {
/* ... */
},
guards: {
/* ... */
},
delays: {
/* ... */
},
}).createMachine({
entry: { type: 'doSomething' },
// ... 机器的其余配置
});
const feedbackActor = createActor(feedbackMachine)
feedbackActor.start();
// logs 'Doing something!'
你可以通过 machine.provide(...)
提供实现来覆盖默认实现。此函数将创建一个具有相同配置但具有提供的实现的新机器:
const customFeedbackMachine = feedbackMachine.provide({
actions: {
doSomething: () => {
console.log('Doing something else!');
},
},
});
const feedbackActor = createActor(customFeedbackMachine)
feedbackActor.start();
// 记录 'Doing something else!'
确定下一个状态
当你创建一个状态机 actor 时,下一个状态由机器的当前状态和发送到 actor 的事件决定。如果你想在 actor 之外确定下一个状态,可以使用 getNextSnapshot(…)
函数:
import { getNextSnapshot } from 'xstate';
import { feedbackMachine } from './feedbackMachine';
const nextSnapshot = getNextSnapshot(
feedbackMachine,
feedbackMachine.resolveState({ value: 'question' }),
{ type: 'feedback.good' }
);
console.log(nextSnapshot.value);
// logs 'thanks'
你还可以使用 getInitialSnapshot(…)
函数确定机器的初始状态:
import { getInitialSnapshot } from 'xstate';
import { feedbackMachine } from './feedbackMachine';
const initialSnapshot = getInitialSnapshot(
feedbackMachine,
// optional input
{ defaultRating: 3 }
);
console.log(initialSnapshot.value);
// logs 'question'
指定类型
你可以在机器设置中使用 .types
属性指定 TypeScript 类型:
import { setup } from 'xstate';
const feedbackMachine = setup({
types: {
context: {} as { feedback: string },
events: {} as
| { type: 'feedback.good' }
| { type: 'feedback.bad' }
},
actions: {
logTelemetry: () => {
// TODO: 实现
}
}
}).createMachine({
// ...
});
这些类型将在整个机器配置以及创建的机器和 actor 中推断出来,以便诸如 machine.transition(...)
和 actor.send(...)
之类的方法将是类型安全的。
类型生成
类型生成 目前尚不支持 XState v5。然而,通过上述的 setup(...)
函数和/或 .types
属性,你可以为你的机器提供强类型支持。
API
即将推出…
机器和 TypeScript
为你的机器提供强类型支持的最佳方式是使用 setup(...)
函数和/或 .types
属性。
import { setup, fromPromise } from 'xstate';
const someAction = () => {/* ... */};
const someGuard = ({ context }) => context.count <= 10;
const someActor = fromPromise(async () => {
// ...
return 42;
});
const feedbackMachine = setup({
types: {
context: {} as { count: number },
events: {} as
| { type: 'increment' }
| { type: 'decrement' }
},
actions: {
someAction
},
guards: {
someGuard
},
actors: {
someActor
}
}).createMachine({
initial: 'counting',
states: {
counting: {
entry: { type: 'someAction' }, // 强类型
invoke: {
src: 'someActor', // 强类型
onDone: {
actions: ({ event }) => {
event.output; // 强类型为 number
}
}
},
on: {
increment: {
guard: { type: 'someGuard' }, // 强类型
actions: assign({
count: ({ context }) => context.count + 1
})
}
},
}
}
});
机器速查表
使用下面的 XState 机器速查表快速入门。
速查表:创建一个机器
import { createMachine } from 'xstate';
const machine = createMachine({
initial: 'start',
states: {
start: {},
// ...
},
});
速查表:设置带有实现的机器
import { setup } from 'xstate';
const machine = setup({
actions: {
someAction: () => {/* ... */}
},
guards: {
someGuard: ({ context }) => context.count <= 10
},
actors: {
someActor: fromPromise(async () => {/* ... */})
},
delays: {
someDelay: () => 1000
}
}).createMachine({
// ... 机器的其余配置
})
速查表:提供实现
import { createMachine } from 'xstate';
import { someMachine } from './someMachine'
const machineWithImpls = someMachine.provide({
actions: {
/* ... */
},
actors: {
/* ... */
},
guards: {
/* ... */
},
delays: {
/* ... */
},
});