Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v5] Recursive persistence #3743

Merged
merged 81 commits into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
a608233
Add PersistedState
davidkpiano Jan 3, 2023
dbfb7d5
Merge branch 'next' into v5/recursive-persistence
davidkpiano Jan 7, 2023
d341071
behavior.at (WIP)
davidkpiano Jan 8, 2023
4ae6151
Use invoke action instead
davidkpiano Jan 9, 2023
76e291a
Ensure that persisted state isn't lost
davidkpiano Jan 9, 2023
3ecca35
Allow machine.at(...) to take optional arg
davidkpiano Jan 9, 2023
2c4f211
Cleanup
davidkpiano Jan 11, 2023
cd9c622
Merge branch 'next' into v5/recursive-persistence
davidkpiano Jan 20, 2023
bbb17ef
Renaming
davidkpiano Jan 20, 2023
a5dd8eb
Fix types
davidkpiano Jan 20, 2023
dd74f9e
No more arguments for .start()
davidkpiano Jan 20, 2023
d1e7fce
Merge branch 'next' into v5/recursive-persistence
davidkpiano Jan 20, 2023
953033f
Merge branch 'next' into v5/recursive-persistence
davidkpiano Jan 21, 2023
6e92889
Improve types/tests
davidkpiano Jan 27, 2023
3769cae
Merge branch 'next' into v5/recursive-persistence
davidkpiano Jan 27, 2023
cbd6b67
Add input with loose types
davidkpiano Jan 29, 2023
9a48360
Update packages/core/src/StateMachine.ts
davidkpiano Feb 1, 2023
d440b5e
Move input closer to the interpreter (#3803)
Andarist Feb 1, 2023
8fb1b29
Update packages/core/src/types.ts
davidkpiano Feb 2, 2023
925fe22
Remove UseMachineOptions (React)
davidkpiano Feb 6, 2023
c21ae81
Remove options from other libraries
davidkpiano Feb 6, 2023
246f3ef
Merge branch 'v5/input-2' into v5/recursive-persistence
davidkpiano Feb 6, 2023
2b5f2ed
Remove public usage of .at(...) in favor of { state: ... }
davidkpiano Feb 6, 2023
dabca9e
Remove .at() (mostly)
davidkpiano Feb 6, 2023
26d9a22
Lint
davidkpiano Feb 6, 2023
8a08bdc
Remove input from this PR
davidkpiano Feb 7, 2023
da08941
Oops
davidkpiano Feb 7, 2023
1517afc
Remove machine.at
davidkpiano Feb 8, 2023
541b6cc
Remove state
davidkpiano Feb 8, 2023
29552aa
Use `machine.getPersistedState`
davidkpiano Feb 13, 2023
2c37941
public preInitialState -> private _preInitialState
davidkpiano Feb 13, 2023
efc4ae4
Remove _preInitialState
davidkpiano Feb 13, 2023
ae13d04
Clarifying comment
davidkpiano Feb 13, 2023
3abcf0b
getPersistedState should use initial state
davidkpiano Feb 13, 2023
8c1a5c2
Use .js at the end
davidkpiano Feb 13, 2023
9c18cbd
start returns void
davidkpiano Feb 13, 2023
9827f16
Add todo
davidkpiano Feb 13, 2023
3f3f460
Lint
davidkpiano Feb 13, 2023
2bdd8c5
Merge branch 'next' into v5/recursive-persistence
davidkpiano Feb 27, 2023
c069959
Attempt to fix types
davidkpiano Feb 27, 2023
22eeaec
Ugh types
davidkpiano Feb 27, 2023
4462f15
Address comments
davidkpiano Mar 1, 2023
19ce012
Add changeset
davidkpiano Mar 1, 2023
07bd0dc
Update .changeset/shy-cobras-ring.md
davidkpiano Mar 1, 2023
ba8fcef
Remove constraint
davidkpiano Mar 1, 2023
4d37b6f
Update packages/core/src/State.ts
davidkpiano Mar 1, 2023
ccdbaa0
Don't do the hacky thing
davidkpiano Mar 1, 2023
b27c40e
Merge branch 'v5/recursive-persistence' of https://github.com/stately…
davidkpiano Mar 1, 2023
3f81e11
Renaming etc
davidkpiano Mar 1, 2023
0f71646
Change PersistedMachineState children shape
davidkpiano Mar 3, 2023
fa7d371
Small tweaks
davidkpiano Mar 3, 2023
a0f547c
Change test, remove action unshifting for starting actors
davidkpiano Mar 4, 2023
4f53c70
Add skipped test
davidkpiano Mar 4, 2023
5dc9f46
Do better here (PersistedMachineState)
davidkpiano Mar 4, 2023
739d8cb
Remove comment
davidkpiano Mar 4, 2023
8c9ae22
Fix promise test
davidkpiano Mar 4, 2023
2b01891
Fix everything
davidkpiano Mar 5, 2023
ecff33b
Add src
davidkpiano Mar 5, 2023
f556d42
Fix types
davidkpiano Mar 5, 2023
544b298
Rename PersistedFrom -> PersistedStateFrom
davidkpiano Mar 5, 2023
e87e818
Sigh, types
davidkpiano Mar 6, 2023
06d65ed
self != this
davidkpiano Mar 7, 2023
b75d480
Add test case: initial state of a child is available before starting …
davidkpiano Mar 7, 2023
1d0c983
Apply suggestion
davidkpiano Mar 7, 2023
c761ca6
Update packages/core/src/StateNode.ts
davidkpiano Mar 7, 2023
ee8ad87
Update packages/core/src/StateMachine.ts
davidkpiano Mar 7, 2023
999ff7d
Update packages/core/src/types.ts
davidkpiano Mar 7, 2023
e58f68c
Made the test work
davidkpiano Mar 8, 2023
3234ac2
fixed types
Andarist Mar 9, 2023
3fb54b4
Initialize the `Interpreter`'s state eagerly (#3874)
Andarist Mar 9, 2023
a170a00
Remove `persisted: true` check
davidkpiano Mar 13, 2023
a087432
Do not restart a completed observable actor
davidkpiano Mar 13, 2023
5253a63
Update packages/core/test/actor.test.ts
davidkpiano Mar 13, 2023
67400de
Update packages/core/test/actor.test.ts
davidkpiano Mar 13, 2023
a8b30b9
Update packages/core/test/actor.test.ts
davidkpiano Mar 13, 2023
ad07b01
Update packages/core/test/actor.test.ts
Andarist Mar 13, 2023
8bdf86b
Add event observable test
davidkpiano Mar 13, 2023
b4f28ba
Fix types
davidkpiano Mar 13, 2023
b6db333
Change back
davidkpiano Mar 14, 2023
55e5952
Add changeset
davidkpiano Mar 14, 2023
7489eb6
Add another changeset
davidkpiano Mar 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .changeset/fast-rockets-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
'xstate': major
---

Restoring persisted state is now done by passing the state into the `state: ...` property of the `interpret` options argument:

```diff
-interpret(machine).start(state);
+interpret(machine, { state }).start();
```

The persisted state is obtained from an actor by calling `actor.getPersistedState()`:

```ts
const actor = interpret(machine).start();

const persistedState = actor.getPersistedState();

// ...

const restoredActor = interpret(machine, {
state: persistedState
}).start();
```
10 changes: 10 additions & 0 deletions .changeset/heavy-ties-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'xstate': major
---

Invoked actors can now be deeply persisted and restored. When the persisted state of an actor is obtained via `actor.getPersistedState()`, the states of all invoked actors are also persisted, if possible. This state can be restored by passing the persisted state into the `state: ...` property of the `interpret` options argument:

```diff
-interpret(machine).start(state);
+interpret(machine, { state }).start();
```
2 changes: 2 additions & 0 deletions .changeset/shy-cobras-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@ const lightMachine = createMachine({

const currentState = 'green';

const nextState = lightMachine.transition(currentState, { type: 'TIMER' })
.value;
const nextState = lightMachine.transition(currentState, {
type: 'TIMER'
}).value;

// => 'yellow'
```
Expand Down Expand Up @@ -278,8 +279,9 @@ const lightMachine = createMachine({

const currentState = 'yellow';

const nextState = lightMachine.transition(currentState, { type: 'TIMER' })
.value;
const nextState = lightMachine.transition(currentState, {
type: 'TIMER'
}).value;
// => {
// red: 'walk'
// }
Expand Down Expand Up @@ -374,8 +376,9 @@ const wordMachine = createMachine({
}
});

const boldState = wordMachine.transition('bold.off', { type: 'TOGGLE_BOLD' })
.value;
const boldState = wordMachine.transition('bold.off', {
type: 'TOGGLE_BOLD'
}).value;

// {
// bold: 'on',
Expand Down
19 changes: 10 additions & 9 deletions docs/fr/guides/communication.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,23 +131,24 @@ The resolved data is placed into a `'done.invoke.<id>'` event, under the `data`
If a Promise rejects, the `onError` transition will be taken with a `{ type: 'error.platform' }` event. The error data is available on the event's `data` property:

```js
const search = (context, event) => new Promise((resolve, reject) => {
if (!event.query.length) {
return reject('No query specified');
// or:
// throw new Error('No query specified');
}
const search = (context, event) =>
new Promise((resolve, reject) => {
if (!event.query.length) {
return reject('No query specified');
// or:
// throw new Error('No query specified');
}

return resolve(getSearchResults(event.query));
});
return resolve(getSearchResults(event.query));
});

// ...
const searchMachine = createMachine({
id: 'search',
initial: 'idle',
context: {
results: undefined,
errorMessage: undefined,
errorMessage: undefined
},
states: {
idle: {
Expand Down
19 changes: 10 additions & 9 deletions docs/zh/guides/communication.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,23 +131,24 @@ const userMachine = createMachine({
如果 Promise 拒绝,则将使用 `{ type: 'error.platform' }` 事件进行 `onError` 转换。 错误数据在事件的 `data` 属性中可用:

```js
const search = (context, event) => new Promise((resolve, reject) => {
if (!event.query.length) {
return reject('No query specified');
// or:
// throw new Error('No query specified');
}
const search = (context, event) =>
new Promise((resolve, reject) => {
if (!event.query.length) {
return reject('No query specified');
// or:
// throw new Error('No query specified');
}

return resolve(getSearchResults(event.query));
});
return resolve(getSearchResults(event.query));
});

// ...
const searchMachine = createMachine({
id: 'search',
initial: 'idle',
context: {
results: undefined,
errorMessage: undefined,
errorMessage: undefined
},
states: {
idle: {
Expand Down
26 changes: 24 additions & 2 deletions packages/core/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
EventObject,
HistoryValue,
MachineContext,
PersistedMachineState,
Prop,
SCXML,
StateConfig,
Expand Down Expand Up @@ -124,7 +125,7 @@ export class State<
return stateValue;
}

const _event = initEvent as SCXML.Event<TEvent>;
const _event = initEvent as SCXML.Event<TEvent>; // TODO: fix

const configuration = getConfiguration(
getStateNodes(machine.root, stateValue)
Expand Down Expand Up @@ -167,7 +168,7 @@ export class State<
this.configuration =
config.configuration ??
Array.from(getConfiguration(getStateNodes(machine.root, config.value)));
this.transitions = config.transitions;
this.transitions = config.transitions as any;
this.children = config.children;

this.value = getStateValue(machine.root, this.configuration);
Expand Down Expand Up @@ -287,3 +288,24 @@ export function cloneState<TState extends AnyState>(
state.machine
) as TState;
}

export function getPersistedState<TState extends AnyState>(
state: TState
): PersistedMachineState<TState> {
const { configuration, transitions, tags, machine, children, ...jsonValues } =
state;

const childrenJson: Partial<PersistedMachineState<any>['children']> = {};

for (const id in children) {
childrenJson[id] = {
state: children[id].getPersistedState?.(),
src: children[id].src
};
}

return {
...jsonValues,
children: childrenJson
} as PersistedMachineState<TState>;
}
Loading