#Help with `spawnChild`

1 messages · Page 1 of 1 (latest)

crisp moon
#

Hi team,

I'm having some trouble with spawning child actors.

I have the following code:

export const gameMachine = setup({
  actions: {
    ...
    playerConnect: enqueueActions(({ context, enqueue, event, self }) => {
      assertEvent(event, EventTypesSchema.enum.PlayerConnect);
      if (!self.getSnapshot().children[event.data.playerId]) {
        enqueue.spawnChild(playerMachine, {
          id: event.data.playerId as never,
          input: PlayerSchema.parse({
            id: event.data.playerId,
          }),
        });
      }

      enqueue.sendTo(event.data.playerId, event);
    }),
    ...
  }
})

and I attempt to persist the parent actor like so:

const persistedSnapshot = this.stateMachine.getPersistedSnapshot();

However, I see an error:
Error: An inline child actor cannot be persisted.

I followed this suggestion to convert it from an inlined actor to a referenced actor like so:

export const gameMachine = setup({
  actors: {
    player: playerMachine
  },
  actions: {
    ...
    playerConnect: enqueueActions(({ context, enqueue, event, self }) => {
        ...
        enqueue.spawnChild("player", {
            ...
          }),
        });
      }
  }
})

however, now I see a new error:

Actor type 'player' not found in machine 'x:13'.

State machine error Error: Unable to send event to actor '7c8e05d4-9d85-4d33-a0aa-8895f29dd157' from machine 'game'.

it seems the parent machine cannot find "player" even though it is referenced in actors in the setup function. I assume this happens on enqueue.sendTo

Any suggestions?

Thank you

crisp moon
#

hmmm...seems it was an issue importing from index files instead of direct file

import { actions, guards, playerMachine } from ".";

import { actions, guards } from ".";
import { playerMachine } from "./player.machine";

that's very odd. Any ideas why this may be the case?
import from index worked when the actor was inlined, but not when referenced 🤔

unique kindle
#

I think you want to use spawn, not spawnChild for your referenced actor https://stately.ai/docs/spawn

You can use spawn to run actors. Actors created with spawn are spawning actors, and actors created with invoke are invoking actors.

crisp moon
#

just made the change. Thank you

#

would you consider making self machine reference available inside guard functions, the same way it's available inside assign ?

my thinking is that the children are already stored references via self.getSnapshot().children

this allows me to forego manually keeping a reference to them.
I use this often in actions, but guard has no self

#

like so

guards: {
      hasPlayers: ({ context, event, self }) => {
        return Object.keys(self.getSnapshot().children).length > 0
      },
    },
unique kindle
crisp moon
#

noted. thank you

#

what is the difference between referencing via self.getSnapshot().children and keeping them in context as a ref via context.childActorRefs?

unique kindle
#

You won't need to read the snapshot and have a proper API to access your refs with type safety

childActorRefs: ActorRefFrom<typeof childMachine>[]