Class: PlayerActor<TMachine>
API / @xmachines/play-xstate / PlayerActor
Defined in: packages/play-xstate/src/player-actor.ts:202
The concrete XState actor. It implements the signal protocol of the Play Architecture
The class extends @xmachines/play-actor!AbstractActor, and therefore the
Actor class of XState. It gives you the XState v5 integration, and it keeps the
compatibility with the ecosystem, such as the XState inspection and the devtools.
The constructor of the base class receives the machine. Therefore a PlayerActor
is the XState actor, and it is no wrapper around one: every member of the
XState Actor class works on the state of this instance, and this class adds the
reactive state on the TC39 Signals for the observation by the infrastructure.
Capabilities: the class implements both the @xmachines/play-actor!Routable interface and the @xmachines/play-actor!Viewable interface. It therefore supports the routing and the view rendering.
Architectural context: the class implements Actor Authority (INV-01),
because the guards of the XState machine control every decision of the
navigation. The infrastructure observes the signals of the actor (state,
currentRoute, and currentView), but it changes no state directly: every
change goes through the event handlers of the state machine.
Examples
The creation of an actor, and its lifecycle
import { setup } from "xstate";import { definePlayer } from "@xmachines/play-xstate";
const machine = setup({}).createMachine({ initial: "idle", states: { idle: { meta: { route: "/", // A view spec needs `root` and `elements`. Every other shape derives null. view: { root: "home", elements: { home: { type: "HomePage", props: {}, children: [] } }, }, }, }, },});
const createPlayer = definePlayer({ machine });const actor = createPlayer();actor.start();
// Observe the signalsconsole.log(actor.currentRoute.get()); // '/'console.log(actor.currentView.get()?.root); // 'home'The signal lifecycle with a watcher
import { Signal } from "@xmachines/play-signals";
const watcher = new Signal.subtle.Watcher(() => { queueMicrotask(() => { const pending = watcher.getPending(); console.log("State changed:", actor.state.get()); });});
watcher.watch(actor.state);actor.send({ type: "play.route", to: "#about" });// The watcher schedules its own notification in a microtaskSee
- Play RFC
- definePlayer for the creation through a factory
- @xmachines/play-actor!AbstractActor for the signal protocol
- @xmachines/play-actor!Routable for the routing capability
- @xmachines/play-actor!Viewable for the view rendering capability
Remarks
The routing: this actor supports the route: {} config pattern of XState and
also a play.route event with parameters. The deriveRoute() function reads
meta.route, which is the Stately pattern, for a URL template, and it substitutes
each parameter.
The pattern of the view signal: the currentView signal is a direct
Signal.State, and not a Signal.Computed. The propagation to a watcher in
PlayRenderer is therefore correct. The class derives each view at the entry of a
state and keeps it, and it computes no view on a read.
Extends
AbstractActor<AnyActorLogic,EventFromLogic<TMachine>>
Type Parameters
| Type Parameter | Description |
|---|---|
TMachine extends AnyStateMachine | The type of the XState v5 state machine |
Implements
Constructors
Constructor
new PlayerActor<TMachine>( machine, options, input?,restoredSnapshot?): PlayerActor<TMachine>;Defined in: packages/play-xstate/src/player-actor.ts:360
Parameters
| Parameter | Type |
|---|---|
machine | TMachine |
options | PlayerOptions<TMachine> |
input? | InputFrom<TMachine> |
restoredSnapshot? | Snapshot<unknown> |
Returns
PlayerActor<TMachine>
Overrides
Properties
| Property | Modifier | Type | Description | Overrides | Inherited from | Defined in |
|---|---|---|---|---|---|---|
_parent? | public | AnyActorRef | - | - | AbstractActor._parent | - |
clock | public | Clock | The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions. | - | AbstractActor.clock | - |
currentRoute | public | Computed<string | null> | A TC39 Signal.Computed. It derives the current URL path from the meta.route template of the active machine state and from the context of the actor. It returns null when the current state has no meta.route field, and also when it cannot resolve the complete route template. A necessary :param that the context does not hold is caught inside the signal, and a MissingRouteParamError therefore never leaves get(): that condition is temporary during a transition, and the signal computes the value again on the next snapshot. Example // It returns "/profile/alice" when context.params.userId === "alice", // and null while the param is still absent. const route = actor.currentRoute.get(); | - | - | packages/play-xstate/src/player-actor.ts:304 |
currentView | readonly | State<PlaySpec | null> | The reactive signal of the current view spec. The signal derives the spec from the meta.view metadata of the active state. It emits a new object reference on each real change of the view on the screen: the view of a different state, or a change of a param or of the context that changes the resolved spec. A re-entry with reenter: true and new params also changes the spec. A snapshot that changes no view on the screen, such as an assign of the context alone, keeps the previous reference. A provider below the signal therefore mounts the UI again not on every event. The PlaySpec of the emission carries the context of the machine in its composed state field, under the read-only /context subtree. A spec therefore reads the context, and also each URL param, through the ordinary state grammar ({ $state: "/context/params/section" }). The context-projection module of @xmachines/play-actor holds the complete contract. The signal returns null when the current state has no meta.view metadata. Two states can declare two separate meta.view literals with an identical structure. A transition between those two states then emits two different references, and a provider mounts the UI again. Move the shared literal into one typedSpec constant, and the identity then removes the duplicate. Example const view = actor.currentView.get(); if (view) { console.log(view.root); // for example "root" console.log(view.elements); // the Spec elements of @xmachines/json-render-core } | - | - | packages/play-xstate/src/player-actor.ts:358 |
id | public | string | The unique identifier for this actor relative to its parent. | - | AbstractActor.id | - |
initialRoute | readonly | string | null | The route of the initial state of the machine. The constructor fixes it, and it never changes, also when the code restores the actor from a snapshot. A router bridge compares it with the browser URL, and it therefore separates a deep link (a URL that is not the initial one → the router wins) from a restore (the initial URL, and the actor at a different route from the restore → the actor wins). deriveInitialRoute derives the value statically from the machine definition, with the pure initialTransition helper of XState: the chain of the initial states and their meta.route templates are fixed at the moment of the machine definition, and the substitution of a :param uses the real initial context of the machine for the input of this actor. The code makes no second actor, and a snapshot of a restore changes the value never: it is always the default initial route of the machine. | - | - | packages/play-xstate/src/player-actor.ts:323 |
logic | public | AnyActorLogic | - | - | AbstractActor.logic | - |
options | public | Readonly<ActorOptions<TLogic>> | - | - | AbstractActor.options | - |
ref | public | ActorRef<any, any, any> | - | - | AbstractActor.ref | - |
sessionId | public | string | The globally unique process ID for this invocation. | - | AbstractActor.sessionId | - |
src | public | | string | AnyActorLogic | - | - | AbstractActor.src | - |
state | public | State<ReturnType<TMachine["transition"]>> | The reactive snapshot of the current actor state. The infrastructure observes this signal, and it reacts to each state change. It therefore holds no coupling to the internal state machine of the actor. | AbstractActor.state | - | packages/play-xstate/src/player-actor.ts:263 |
system | public | AnyActorSystem | The system to which this actor belongs. | - | AbstractActor.system | - |
systemId | public | string | undefined | - | - | AbstractActor.systemId | - |
Methods
[observable]()
observable: InteropSubscribable<any>;Defined in: xstate
Returns
InteropSubscribable<any>
Inherited from
can()
can(event): boolean;Defined in: packages/play-xstate/src/player-actor.ts:276
Tells you if the current state of the actor accepts the given event.
The type is the event union of the machine. An unknown event type is therefore a compile error. The method evaluates the event against the snapshot signal.
Parameters
| Parameter | Type |
|---|---|
event | EventFromLogic<TMachine> |
Returns
boolean
Example
if (actor.can({ type: "auth.logout" })) { ... }dispose()
dispose(): void;Defined in: packages/play-xstate/src/player-actor.ts:751
The dispose method, for the cleanup. It is the alias of stop.
Returns
void
Deprecated
Use stop. Will be removed in the next major.
getPersistedSnapshot()
getPersistedSnapshot(options?): Snapshot<unknown>;Defined in: packages/play-xstate/src/player-actor.ts:696
Returns the persisted snapshot of this actor.
Use it to serialize the state, and to restore it later with the
restore.snapshot option of the factory.
Parameters
| Parameter | Type |
|---|---|
options? | unknown |
Returns
Snapshot<unknown>
Overrides
AbstractActor.getPersistedSnapshot
getSnapshot()
getSnapshot(): SnapshotFrom<TMachine>;Defined in: packages/play-xstate/src/player-actor.ts:595
Returns the current snapshot
Returns
SnapshotFrom<TMachine>
Overrides
on()
on<TType>(type, handler): Subscription;Defined in: packages/play-xstate/src/player-actor.ts:681
Listens for the events that this actor emits with the emit action.
Type Parameters
| Type Parameter |
|---|
TType extends any |
Parameters
| Parameter | Type | Description |
|---|---|---|
type | TType | The type of the emitted event to listen for, or "*" for every event. |
handler | (emitted) => void | The actor calls it with each emitted event that matches. |
Returns
The subscription, with an unsubscribe() method.
Overrides
select()
select<TSelected>(selector, equalityFn?): Readable<TSelected>;Defined in: xstate
Type Parameters
| Type Parameter |
|---|
TSelected |
Parameters
| Parameter | Type |
|---|---|
selector | (snapshot) => TSelected |
equalityFn? | (a, b) => boolean |
Returns
Readable<TSelected>
Inherited from
send()
send(event): void;Defined in: packages/play-xstate/src/player-actor.ts:556
Sends an event to this actor.
The guards of the state machine of the actor decide if the event causes a transition. Give any event of the event union of the machine: a domain event, a routing event, and so on.
Parameters
| Parameter | Type | Description |
|---|---|---|
event | EventFromLogic<TMachine> | An event of the EventFromLogic<TMachine> union of the machine. |
Returns
void
Throws
When event is not a plain object, for example
null, undefined, a string, or a number. Import the class from
@xmachines/play-xstate/errors.
Example
// A domain event, with the type of the event union of the machineactor.send({ type: "auth.login", userId: "123" });
// A routing eventactor.send({ type: "play.route", to: "#home" });Overrides
start()
start(): this;Defined in: packages/play-xstate/src/player-actor.ts:482
Starts the actor.
The method fires onStart on each real start, which is every transition from
“not running” to “running”. A start after a stop is such a transition, and XState
permits it: its own start() stops only while the actor RUNS already. A second
call while the actor runs fires no hook. Therefore a defensive double mount runs
the side effects of onStart one time for one real start.
Returns
this
Overrides
stop()
stop(): this;Defined in: packages/play-xstate/src/player-actor.ts:512
Stops the actor and cleans up.
The method fires onStop only when the actor ran. This matches XState, where a
stop of an actor that never started, or of an actor that stopped already, does
nothing and tears nothing down. Therefore the paired cleanup runs never two
times, and it runs never against a resource that onStart did not take. A stop
does not close the actor for ever: a later start() is a new lifecycle, and it
fires onStart again.
Returns
this
Overrides
subscribe()
Call Signature
subscribe(observer): Subscription;Defined in: packages/play-xstate/src/player-actor.ts:618
Subscribes to the snapshot updates of this actor.
The method accepts an observer object, exactly like Actor.subscribe of XState.
Parameters
| Parameter | Type | Description |
|---|---|---|
observer | Observer<SnapshotFrom<TMachine>> | The observer, with a next, an error, and a complete handler. |
Returns
The subscription, with an unsubscribe() method.
Overrides
Call Signature
subscribe( nextListener?, errorListener?, completeListener?): Subscription;Defined in: packages/play-xstate/src/player-actor.ts:629
Subscribes to the snapshot updates of this actor.
The method accepts listener functions, exactly like Actor.subscribe of XState.
Parameters
| Parameter | Type | Description |
|---|---|---|
nextListener? | (snapshot) => void | The listener function of each snapshot. |
errorListener? | (error) => void | The actor calls it on an error. |
completeListener? | () => void | The actor calls it when it completes, which means that it reaches a final state. |
Returns
The subscription, with an unsubscribe() method.
Overrides
toJSON()
toJSON(): object;Defined in: xstate
Returns
object
| Name | Type | Defined in |
|---|---|---|
id | string | - |
xstate$$type | number | - |