持久化
Actors 可以持久化其内部状态并在以后恢复。持久化是指将 actor 的状态存储在持久存储中,例如 localStorage 或数据库。恢复是指从持久存储中恢复 actor 的状态。
在前端应用程序中,持久化对于在浏览器重新加载时保持状态非常有用。在后端应用程序中,持久化允许工作流跨多个请求,能够在服务重启时存活,具有容错能力,能够表示长时间运行的进程,并且可以进行审计和追踪。
在 XState 中,你可以通过 actor.getPersistedSnapshot()
获取要持久化的快照(状态),并通过 createActor(behavior, { snapshot: restoredState }).start()
恢复它:
const feedbackActor = createActor(feedbackMachine).start();
// 获取要持久化的状态
const persistedState = feedbackActor.getPersistedSnapshot();
// 持久化状态
localStorage.setItem('feedback', JSON.stringify(persistedState));
// 恢复状态
const restoredState = JSON.parse(localStorage.getItem('feedback'));
const restoredFeedbackActor = createActor(feedbackMachine, {
snapshot: restoredState,
}).start();
持久化状态
你可以通过 actor.getPersistedSnapshot()
获取要持久化的状态:
const feedbackActor = createActor(feedbackMachine).start();
// 获取要持久化的状态
const persistedState = feedbackActor.getPersistedSnapshot();
内部状态可以从任何 actor 持久化,而不仅仅是状态机。请注意,持久化状态与 actor.getSnapshot()
的快照不同;持久化状态表示 actor 的内部状态,而快照表示 actor 最后发出的值:
const promiseActor = fromPromise(() => Promise.resolve(42));
// 获取最后发出的值
const snapshot = promiseActor.getSnapshot();
console.log(snapshot);
// 输出 42
// 获取持久化状态
const persistedState = promiseActor.getPersistedSnapshot();
console.log(persistedState);
// 输出 { status: 'done', data: 42 }
恢复状态
你可以通过将持久化状态传递给 createActor(logic, { snapshot: restoredState })
的第二个参数中的 state
选项来恢复 actor 到持久化状态:
// 获取持久化状态
const restoredState = JSON.parse(localStorage.getItem('feedback'));
// 恢复状态
const feedbackActor = createActor(feedbackMachine, {
snapshot: restoredState,
});
feedbackActor.start();
来自机器 actor 的动作将 不会 被重新执行,因为它们被假定已经执行过。然而,调用将被重新启动,并且生成的 actor 将被递归恢复。
深度持久化
从机器 actor 持久化和恢复状态是深度的;所有 调用的 和 生成的 actor 将被递归持久化和恢复。
const feedbackMachine = createMachine({
// ...
states: {
form: {
invoke: {
id: 'form',
src: formMachine,
},
},
},
});
const feedbackActor = createActor(feedbackMachine).start();
// 持久化状态
const persistedState = feedbackActor.getPersistedSnapshot();
localStorage.setItem('feedback', JSON.stringify(persistedState));
// ...
// 恢复状态
const restoredState = JSON.parse(localStorage.getItem('feedback'));
const restoredFeedbackActor = createActor(feedbackMachine, {
snapshot: restoredState,
}).start();
// 将会在持久化状态下恢复 feedbackActor 和调用的 form actor
持久化状态机值
如果你只想持久化状态机 actor 的有限状态 value
(以及可选的 context
),你可以使用 machine.resolveState(...)
方法:
import { someMachine } from './someMachine';
const restoredStateValue = localStorage.getItem('someState');
// 假设这是 "pending"
const resolvedState = someMachine.resolveState({
value: restoredStateValue,
// context: { ... }
});
// 恢复 actor
const restoredActor = createActor(someMachine, {
snapshot: resolvedState
});
restoredActor.start();
事件溯源
持久化状态的另一种方法是事件溯源,这是一种通过重放导致该状态的事件来恢复 actor 状态的方法。事件溯源比持久化状态更可靠,因为它不太容易出现不兼容状态,并且还允许你重放动作。
实现事件溯源的一种方法是使用检查 API在事件发生时持久化事件,然后重放它们以恢复 actor 的状态:
const events = [];
const someActor = createActor(someMachine, {
// 检查并持久化事件
inspect: (inspectionEvent) => {
if (inspectionEvent.type === '@xstate.event') {
const event = inspectionEvent.event;
// 仅监听发送到根 actor 的事件
if (inspectionEvent.actorRef !== someActor) { return; }
events.push(event);
}
}
});
someActor.start();
// ...
// 假设事件存储在某个地方,例如 localStorage,
// 你可以重放它们来恢复 actor 的状态
const restoredActor = createActor(someMachine);
restoredActor.start();
for (const event of events) {
// 重放事件
restoredActor.send(event);
}
注意事项
在持久化和恢复状态时,你应该注意以下几点:
- 不兼容状态:如果机器或 actor 逻辑发生变化,恢复的状态可能与新逻辑不兼容。
- 重放动作:已经执行过的动作将不会被重新执行。对于这种情况,推荐使用事件溯源。
- 序列化:状态必须是可序列化的,这意味着它必须是 JSON 可序列化的。这意味着你不能持久化函数、类或其他不可序列化的值。
持久化速查表
速查表:持久化状态
const persistedState = actor.getPersistedSnapshot();
Cheatsheet: restoring state
const restoredState = JSON.parse(localStorage.getItem('feedback'));
const restoredActor = createActor(actorMachine, {
snapshot: restoredState,
}).start();