Skip to content

Commit 5d4c356

Browse files
authored
Merge pull request #211 from statelyai/davidkpiano/update-actor-docs
Update actor docs with new snapshot changes
2 parents 8050cdf + 5f47d70 commit 5d4c356

File tree

1 file changed

+63
-16
lines changed

1 file changed

+63
-16
lines changed

docs/actors.mdx

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ import { createActor } from 'xstate';
6060
import { someActorLogic } from './someActorLogic.ts';
6161

6262
const actor = createActor(someActorLogic);
63+
64+
actor.subscribe((snapshot) => {
65+
console.log(snapshot);
66+
});
67+
6368
actor.start();
6469

6570
// Now the actor can receive events
@@ -88,24 +93,32 @@ An example of the difference between invoking and spawning actors could occur in
8893

8994
When an actor receives an event, its internal state may change. An actor may emit a **snapshot** when a state transition occurs. You can read an actor’s snapshot synchronously via `actor.getSnapshot()`.
9095

91-
An actor’s snapshot is not necessarily the same as its internal state; instead, it is a value the actor wants to _share_ with subscribers. For example, a promise actor has an internal state consisting of `data`, `status`, and other internal properties, but only the `data` is emitted as its snapshot.
92-
9396
```ts
9497
import { fromPromise, createActor } from 'xstate';
9598

99+
async function fetchCount() {
100+
return Promise.resolve(42);
101+
}
102+
96103
const countLogic = fromPromise(async () => {
97104
const count = await fetchCount();
98105

99106
return count;
100107
});
101108

102109
const countActor = createActor(countLogic);
110+
103111
countActor.start();
104112

105113
countActor.getSnapshot(); // logs undefined
106114

107115
// After the promise resolves...
108-
countActor.getSnapshot(); // logs 42
116+
countActor.getSnapshot();
117+
// => {
118+
// output: 42,
119+
// status: 'done',
120+
// ...
121+
// }
109122
```
110123

111124
You can subscribe to an actor’s snapshot values via `actor.subscribe(observer)`. The observer will receive the actor’s snapshot value when it is emitted. The observer can be:
@@ -126,7 +139,7 @@ const subscription = actor.subscribe({
126139
next(snapshot) {
127140
console.log(snapshot);
128141
},
129-
error(data) {
142+
error(err) {
130143
// ...
131144
},
132145
complete() {
@@ -146,21 +159,26 @@ const subscription = actor.subscribe((snapshot) => {
146159
subscription.unsubscribe();
147160
```
148161

149-
When the actor is stopped, all observers will automatically be unsubscribed.
150-
151-
You can initialize actor logic at a specific persisted internal state by passing the state in the second `options` argument of `createActor(logic, options)`. If the state is compatible with the actor logic, this will create an actor that will be started at that persisted state:
162+
When the actor is stopped, all of its observers will automatically be unsubscribed.
152163

153164
You can initialize actor logic at a specific persisted internal state by passing the state in the second `options` argument of `createActor(logic, options)`. If the state is compatible with the actor logic, this will create an actor that will be started at that persisted state:
154165

155166
```ts
156-
const persistedState = JSON.parse(localStorage.get('some-persisted-state'));
167+
const persistedState = JSON.parse(localStorage.getItem('some-persisted-state'));
157168

158169
const actor = createActor(someLogic, {
159170
// highlight-start
160171
state: persistedState,
161172
// highlight-end
162173
});
163174

175+
actor.subscribe(() => {
176+
localStorage.setItem(
177+
'some-persisted-state',
178+
JSON.stringify(actor.getPersistedState()),
179+
);
180+
});
181+
164182
// Actor will start at persisted state
165183
actor.start();
166184
```
@@ -176,15 +194,21 @@ You can wait for an actor’s snapshot to satisfy a predicate using the `waitFor
176194
- Rejected if an error is thrown or the `options.timeout` value is elapsed.
177195

178196
```ts
179-
await waitFor(
197+
import { waitFor } from 'xstate';
198+
import { countActor } from './countActor.ts';
199+
200+
const snapshot = await waitFor(
180201
countActor,
181202
(snapshot) => {
182-
return snapshot.count >= 100;
203+
return snapshot.context.count >= 100;
183204
},
184205
{
185206
timeout: 10_000, // 10 seconds (10,000 milliseconds)
186207
},
187208
);
209+
210+
console.log(snapshot.output);
211+
// => 100
188212
```
189213

190214
## State machine actor logic
@@ -199,6 +223,7 @@ You can describe actor logic as a [state machine](machines.mdx). Actors created
199223

200224
```ts
201225
const toggleMachine = createMachine({
226+
id: 'toggle',
202227
initial: 'inactive',
203228
states: {
204229
inactive: {},
@@ -207,6 +232,7 @@ const toggleMachine = createMachine({
207232
});
208233

209234
const toggleActor = createActor(toggleMachine);
235+
210236
toggleActor.subscribe((snapshot) => {
211237
// snapshot is the machine's state
212238
console.log('state', snapshot.value);
@@ -229,21 +255,29 @@ Sending events to promise actors will have no effect.
229255

230256
```ts
231257
const promiseLogic = fromPromise(() => {
232-
return fetch('...').then((data) => data.json());
258+
return fetch('https://example.com/...').then((data) => data.json());
233259
});
234260

235261
const promiseActor = createActor(promiseLogic);
236262
promiseActor.subscribe((snapshot) => {
237263
console.log(snapshot);
238264
});
239265
promiseActor.start();
240-
// Logs undefined
266+
// => {
267+
// output: undefined,
268+
// status: 'active'
269+
// ...
270+
// }
241271

242272
// After promise resolves
243-
// Logs user: { name: ... }
273+
// => {
274+
// output: { ... },
275+
// status: 'done',
276+
// ...
277+
// }
244278
```
245279

246-
## Transition actors
280+
## Transition function actors
247281

248282
Transition actor logic is described by a [transition function](migration.mdx#use-actor-logic-creators-for-invokesrc-instead-of-functions), similar to a [reducer](cheatsheet.mdx#creating-transition-logic). Transition functions take the current `state` and received `event` object as arguments, and return the next state. Actors created from transition logic (“transition actors”) can:
249283

@@ -269,10 +303,18 @@ transitionActor.subscribe((snapshot) => {
269303
console.log(snapshot);
270304
});
271305
transitionActor.start();
272-
// Logs { count: 0 }
306+
// => {
307+
// status: 'active',
308+
// context: { count: 0 },
309+
// ...
310+
// }
273311

274312
transitionActor.send({ type: 'increment' });
275-
// Logs { count: 1 }
313+
// => {
314+
// status: 'active',
315+
// context: { count: 1 },
316+
// ...
317+
// }
276318
```
277319

278320
## Observable actors
@@ -287,6 +329,11 @@ Sending events to observable actors will have no effect.
287329
const secondLogic = fromObservable(() => interval(1000));
288330

289331
const secondActor = createActor(secondLogic);
332+
333+
secondActor.subscribe((snapshot) => {
334+
console.log(snapshot.context);
335+
});
336+
290337
secondActor.start();
291338
// At every second:
292339
// Logs 0

0 commit comments

Comments
 (0)