Skip to content

Latest commit

 

History

History
87 lines (58 loc) · 3.36 KB

File metadata and controls

87 lines (58 loc) · 3.36 KB

Atom and UI integration

Import the framework-neutral adapter from one subpath:

import * as ActorAtom from "effect-machine/atom";

The actor remains the state owner. A writable Actor Atom reads actor state and sends actor events.

const stateAtom = ActorAtom.make(actor);
const countAtom = ActorAtom.select(stateAtom, (state) => state.count);

Acquire a named actor from an ActorSystem with a typed key. The acquisition suspends while the key is absent. It follows a later actor generation without a second actor registry.

const CounterActor = actorSystemKey<CounterState, CounterEvent>("counter");
const actorAtom = ActorAtom.acquire(system, CounterActor);
const actor = useAtomSuspense(actorAtom).value;

Use ActorAtom.fromSystem(system, key) when the UI must render absence as Option.none() instead of suspending.

Selected Atoms publish only when their selected value changes. Pass an equality function when the selector returns a new object.

const totalAtom = ActorAtom.select(
  stateAtom,
  (state) => ({ cents: state.totalCents }),
  (value, next) => value.cents === next.cents,
);

ActorAtom.lifecycle(actor) exposes actor startup and exit. ActorAtom.latestTransition(actor) exposes the last accepted edge. Both retain their terminal value.

Transition capability

Create one reactive capability Atom for an event:

const canCheckoutAtom = ActorAtom.can(actor, Event.Checkout);

The Atom evaluates the same .when() predicates as the actor. It supports Boolean and Effect predicates. It reevaluates after actor state changes. Effect predicates use the context captured by the actor. React can read it with useAtomSuspense. Solid can read it with useAtomResource.

The Atom gives the UI a preview. The actor evaluates the predicate again when it processes the event. Use actor.call(event) when the caller must inspect the authoritative transitioned result.

Suspense-owned actor startup

Create the actor as an Effect Atom value:

const actorAtom = Atom.make(Machine.scoped(spawnActor));
  • React reads it with useAtomSuspense.
  • Solid reads it with useAtomResource inside Suspense.
  • The Atom registry scope owns actor cleanup.

Selectors and renders

Subscribe to domain selections. Do not subscribe every component to the complete state.

  • The React performance test proves that a label change does not render the count or status view.
  • The Solid performance test proves that a label change does not run the count or status computation.
  • A selected view updates once when its selected value changes.

Exit animations

An external store can publish the next state before an exit animation removes the old tree. Do not repair this with a component hook that keeps an arbitrary last value.

Model the retained display value in the machine state:

const ScreenState = State({
  Active: { title: Schema.String },
  Done: { title: Schema.String },
});

machine.on(ScreenState.Active, Event.Finish, ({ state }) => ScreenState.Done.with(state));

The old tree can read title during exit. The final state is still available after the actor exits.

See the working React application, React render test, Solid application, and Solid computation test.