Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/statelyai/xstate/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The fromActorRef function subscribes to an existing actor and returns a tracked accessor function for its snapshot. It integrates with SolidJS’s reactivity system for fine-grained updates.
function fromActorRef<TActor extends AnyActorRef | undefined>(
  actorRef: Accessor<TActor> | TActor
): Accessor<SnapshotFrom<NonNullable<TActor>> | undefined>

Basic Usage

import { useActorRef, fromActorRef } from '@xstate/solid';
import { createMachine } from 'xstate';

const machine = createMachine({
  context: { count: 0 },
  // ...
});

export const App = () => {
  const actorRef = useActorRef(machine);
  const snapshot = fromActorRef(actorRef);

  return (
    <div>
      <p>Count: {snapshot()?.context.count}</p>
      <button onclick={() => actorRef.send({ type: 'INCREMENT' })}>
        Increment
      </button>
    </div>
  );
};

Reactive Actor Reference

You can pass either a static actor ref or an accessor function:
import { fromActorRef } from '@xstate/solid';
import { createActor } from 'xstate';
import { myMachine } from './myMachine';

const actorRef = createActor(myMachine).start();

export const App = () => {
  // Pass actor ref directly
  const snapshot = fromActorRef(actorRef);

  return <div>State: {snapshot()?.value}</div>;
};

Granular Reactivity

The snapshot accessor integrates with SolidJS’s reactivity system:
import { useActor, fromActorRef } from '@xstate/solid';
import { createMemo } from 'solid-js';
import { myMachine } from './myMachine';

export const App = () => {
  const [, , actorRef] = useActor(myMachine);
  const snapshot = fromActorRef(actorRef);

  // These memos only re-compute when their accessed properties change
  const count = createMemo(() => snapshot()?.context.count);
  const name = createMemo(() => snapshot()?.context.name);
  const isActive = createMemo(() => snapshot()?.matches('active'));

  return (
    <div>
      <p>Count: {count()}</p>
      <p>Name: {name()}</p>
      <p>Active: {isActive() ? 'Yes' : 'No'}</p>
    </div>
  );
};

Undefined Handling

The accessor can return undefined if the actor doesn’t exist:
import { fromActorRef } from '@xstate/solid';
import { createSignal, Show } from 'solid-js';
import { createActor } from 'xstate';
import { myMachine } from './myMachine';

export const App = () => {
  const [actorRef, setActorRef] = createSignal();
  const snapshot = fromActorRef(actorRef);

  const createActor = () => {
    setActorRef(createActor(myMachine).start());
  };

  return (
    <div>
      <Show when={snapshot()} fallback={<p>No actor</p>}>
        <p>State: {snapshot()?.value}</p>
      </Show>
      <button onclick={createActor}>Create Actor</button>
    </div>
  );
};

Selecting Specific Values

Derive specific values from the snapshot:
import { useActor, fromActorRef } from '@xstate/solid';
import { createMemo } from 'solid-js';
import { largeMachine } from './largeMachine';

export const Username = () => {
  const [, , actorRef] = useActor(largeMachine);
  const snapshot = fromActorRef(actorRef);

  // Component only re-renders when username changes
  const username = createMemo(() => snapshot()?.context.user.name);

  return <div>Username: {username()}</div>;
};

export const Counter = () => {
  const [, , actorRef] = useActor(largeMachine);
  const snapshot = fromActorRef(actorRef);

  // Component only re-renders when count changes
  const count = createMemo(() => snapshot()?.context.count);

  return <div>Count: {count()}</div>;
};

Multiple Snapshots

Subscribe to multiple actors:
import { useActorRef, fromActorRef } from '@xstate/solid';
import { authMachine, dataMachine } from './machines';

export const Dashboard = () => {
  const authRef = useActorRef(authMachine);
  const dataRef = useActorRef(dataMachine);

  const authSnapshot = fromActorRef(authRef);
  const dataSnapshot = fromActorRef(dataRef);

  return (
    <div>
      <p>Auth: {authSnapshot()?.value}</p>
      <p>Data: {dataSnapshot()?.value}</p>
    </div>
  );
};

With Effects

Use createEffect to react to snapshot changes:
import { useActor, fromActorRef } from '@xstate/solid';
import { createEffect } from 'solid-js';
import { myMachine } from './myMachine';

export const App = () => {
  const [, , actorRef] = useActor(myMachine);
  const snapshot = fromActorRef(actorRef);

  // Effect runs when snapshot changes
  createEffect(() => {
    const current = snapshot();
    if (current?.matches('success')) {
      console.log('Success!', current.context);
    }
  });

  return <div>{/* ... */}</div>;
};

Comparison with useActor

import { useActor } from '@xstate/solid';
import { myMachine } from './myMachine';

export const App = () => {
  // Creates actor, returns [snapshot, send, actorRef]
  const [snapshot, send] = useActor(myMachine);

  return (
    <div>
      <p>State: {snapshot.value}</p>
      <button onclick={() => send({ type: 'NEXT' })}>
        Next
      </button>
    </div>
  );
};
Use useActor when you need the full tuple. Use fromActorRef when:
  • You already have an actor ref
  • You’re working with spawned/child actors
  • You need more control over subscriptions

TypeScript

The function is fully typed:
import { setup } from 'xstate';
import { useActor, fromActorRef } from '@xstate/solid';
import type { Accessor } from 'solid-js';

interface User {
  id: string;
  name: string;
}

const machine = setup({
  types: {
    context: {} as {
      user: User;
      count: number;
    }
  }
}).createMachine({
  context: {
    user: { id: '1', name: 'Alice' },
    count: 0
  }
});

export const App = () => {
  const [, , actorRef] = useActor(machine);
  const snapshot = fromActorRef(actorRef);

  // TypeScript infers the snapshot type
  const userName: Accessor<string | undefined> = () => {
    return snapshot()?.context.user.name;
  };

  return <div>User: {userName()}</div>;
};

Implementation Details

The fromActorRef function:
  1. Creates a memo to track the actor ref (if passed as accessor)
  2. Uses createImmutable to create a tracked snapshot store
  3. Uses createEffect to subscribe to actor changes
  4. Updates the store with new snapshots
  5. Handles actor switching by resubscribing
  6. Automatically unsubscribes on cleanup via onCleanup
  7. Returns an accessor function for the current snapshot

useActor

Create and manage actors with tracked snapshots

Solid Integration

Back to Solid integration overview

Build docs developers (and LLMs) love