#sendTo problem

1 messages · Page 1 of 1 (latest)

burnt holly
#

The following snippet is an entry: action, I am using inspect to log every inspEvent, and can see the action being called in the log ([Debug] StateMachineService @xstate.action actor: quickPickMachine action.type: sendQuickPickMachineDoneEventToParent), and I can see the logger message in the log ([Debug] sendQuickPickMachineDoneEventToParent, received event type is xstate.done.actor.quickPickMachineActor, sendingTo x:0). But I don't see the 'QUICKPICK_DONE' event in the inspect stream, and the parent machine is not reacting as expected (transitioning). So I must have done something wrong in writing the sendTo. Could someone kindly point out what I've done wrong? TIA!

    sendQuickPickMachineDoneEventToParent: ({ context, event }) => {
      context.logger.log(
        `sendQuickPickMachineDoneEvent, received event type is ${event.type}, sendingTo ${context.parent.id}`,
        LogLevel.Debug,
      );
      sendTo(context.parent, {
        type: 'QUICKPICK_DONE',
      });
    },
flint torrent
#

sendTo returns the action that the machine will run so using it like this doesn't do anything

#

For dynamic usage this block from the docs should help: ts const machine = createMachine({ on: { transmit: { actions: sendTo('someActor', ({ context, event }) => { return { type: 'someEvent', data: context.someData }; }), }, }, }); https://stately.ai/docs/actions#send-to-action

Actions are fire-and-forget effects. When a state machine transitions, it may execute actions. Actions occur in response to events, and are typically defined on transitions in the actions [...] property, or for any transition that exits a state in the state's exit: [...] property.

#

Basically, move your handler to inside the sendTo parameters

burnt holly
#

Thanks to your pointer @flint torrent, I was able to get this to work:
entry: sendTo(({ context }) => context.parent, { type: 'QUICKPICK_DONE' })
Thank you!
But I'd still like to learn the correct syntax so that I can design typesafe, V6-compatible actions with parameters... That's next...

flint torrent
#
const machine = createMachine({
  on: {
    transmit: {
      actions: sendTo('someActor', (_, { someData }: { someData: any[] }) => {
        return { type: 'someEvent', data: someData };
      }),
    },
  },
});```
burnt holly
#

Thank you for that, but that is an inline action, and it's not quite what I'm striving for...
This is the definition of an action ( I changed its name...) in my machine's `setup...

#
setup(
/*... */
actions: {
tellSomeoneImFinishedAction: (
  _,
  params: {
   logger: IScopedLogger;
   sendToTargetActorRef: ActorRef<any, any>;
   eventCausingTheTransitionIntoOuterDoneState: any;  // ToDo: I should type this...
  },
 ) => {
  params.logger.log(
   `tellSomeoneImFinishedAction, eventCausingTheTransitionIntoOuterDoneState is ${params.eventCausingTheTransitionIntoOuterDoneState.type}, sendingTo ${params.sendToTargetActorRef.id}`, LogLevel.Debug);
  // discriminate on the event that triggers this action and send QUICKPICK_DONE or DISPOSE_COMPLETE
  let _eventToSend: { type: 'QUICKPICK_DONE' } | { type: 'DISPOSE_COMPLETE' };
  switch (params.eventCausingTheTransitionIntoOuterDoneState.type) {
   case 'xstate.done.actor.quickPickActor':
    _eventToSend = { type: 'QUICKPICK_DONE' };
    break;
   case 'xstate.done.actor.disposeActor':
    _eventToSend = { type: 'DISPOSE_COMPLETE' };
    break;
    default:
     throw new Error( `tellSomeoneImFinishedAction received an unexpected event type: ${params.eventCausingTheTransitionIntoOuterDoneState.type}`,);
 }
 // can't quite puzzle out how to get it to return the sendTo Action to be executed
 // none of the following work... I just tried throwing a bunch of different syntax at it to see if anything sticks...
 return sendTo(params.sendToTargetActorRef, _eventToSend); // this is the one I expected to work...  It doesn't...
 // return sendTo(() => params.sendToTargetActorRef, _eventToSend);
 // ... None of the following are even syntactically correct
 // return sendTo(() => {params.sendToTargetActorRef, _eventToSend;});
 // return sendTo((params) => params.sendToTargetActorRef, _eventToSend);
 // return sendTo((params) => {params.sendToTargetActorRef, _eventToSend});
 // return sendTo(({params}) => params.sendToTargetActorRef, _eventToSend);
},
},
)
#

I can successfully call this action in the entry property of the outerDoneState, like this:

outerDoneState: {
  type: 'final',
  entry: [
   {
     type: 'tellSomeoneImFinishedAction',
     params: ({ context, event }) => ({
       logger: context.logger,
       sendToTargetActorRef: context.parent,
       eventCausingTheTransitionIntoOuterDoneState: event,
     }),
   },
    //sendTo(({ context }) => context.parent, { type: 'QUICKPICK_DONE' }), // just FYI, this line, if uncommented, will work...
  ],
},

inspect shows the action is called and the logger logs the fact that the action was called, with correct parameters, but the parent doesn't get the event...

flint torrent
#

You are still using a lambda function that returns sendTo instead of sendTo containing the lambda. There is no difference between an inline action vs an action defined in setup, they are just in different places

flint torrent
#
setup({
/*... */
actions: {
tellSomeoneImFinishedAction: sendTo(( _, params) => params.sendToTargetActorRef, (
  _,
  params: {
   logger: IScopedLogger;
   sendToTargetActorRef: ActorRef<any, any>;
   eventCausingTheTransitionIntoOuterDoneState: any;  // ToDo: I should type this...
  },
 ) => {
  params.logger.log(
   `tellSomeoneImFinishedAction, eventCausingTheTransitionIntoOuterDoneState is ${params.eventCausingTheTransitionIntoOuterDoneState.type}, sendingTo ${params.sendToTargetActorRef.id}`, LogLevel.Debug);
  // discriminate on the event that triggers this action and send QUICKPICK_DONE or DISPOSE_COMPLETE
  let _eventToSend: { type: 'QUICKPICK_DONE' } | { type: 'DISPOSE_COMPLETE' };
  switch (params.eventCausingTheTransitionIntoOuterDoneState.type) {
   case 'xstate.done.actor.quickPickActor':
    _eventToSend = { type: 'QUICKPICK_DONE' };
    break;
   case 'xstate.done.actor.disposeActor':
    _eventToSend = { type: 'DISPOSE_COMPLETE' };
    break;
    default:
     throw new Error( `tellSomeoneImFinishedAction received an unexpected event type: ${params.eventCausingTheTransitionIntoOuterDoneState.type}`)
  }

  return _eventToSend
}
)}})  ```

That should work but I'm typing on my phone so I can't test it fully
grand scarab
#

You typed that on your phone? 😳

burnt holly
#

Thank You @flint torrent ! I started my xState journey about 10 weeks ago, and your answer really cleared up a lot of xState action stuff for me. To summarize, the sendTo(...) is a special action that can go wherever an action can go.
It has two arguments, either or both of which can be a lambda that closes over their params argument.
The first lambda must return an actorRef, and the second lambda must return an event, thus satisfying the two argument types that sendTo(...) expects

export interface INotifyCompleteActionParameters {
  logger: IScopedLogger;
  sendToTargetActorRef: ActorRef<any, any>;
  eventCausingTheTransitionIntoOuterDoneState: QuickPickMachineCompletionEventsT;
}
setup(
 actions:{
 notifyCompleteAction: sendTo(
  (_, params: INotifyCompleteActionParameters) => {
   params.logger.log(`notifyCompleteAction, in the destination selector lambda, sendToTargetActorRef is ${params.sendToTargetActorRef.id}`, LogLevel.Debug,);
    return params.sendToTargetActorRef;
  },
  (_, params: INotifyCompleteActionParameters) => {
    params.logger.log(`notifyCompleteAction, in the event selector lambda, eventCausingTheTransitionIntoOuterDoneState is ${params.eventCausingTheTransitionIntoOuterDoneState.type}`, LogLevel.Debug, );
  let _eventToSend: { type: 'QUICKPICK_DONE' } | { type: 'DISPOSE_COMPLETE' };
  switch (params.eventCausingTheTransitionIntoOuterDoneState.type) {
   case 'xstate.done.actor.quickPickActor':
    _eventToSend = { type: 'QUICKPICK_DONE' };
    break;
   case 'xstate.done.actor.quickPickDisposeActor':
    _eventToSend = { type: 'DISPOSE_COMPLETE' };
    break:
      default:
        throw new Error(`notifyCompleteAction received an unexpected event type: ${params.eventCausingTheTransitionIntoOuterDoneState.type}`,);
    }
    params.logger.log(`notifyCompleteAction, in the event selector lambda, _eventToSend is ${_eventToSend.type}`, LogLevel.Debug,);
    return _eventToSend;
  },
 ),
},
).createMachine(
#
/*...*/
outerDoneState: {
  type: 'final',
  entry: [
   // call the notifyComplete action here, setting the value of the params' properties to
   //  values pulled from the context and from the event that entered the outerDonestate.
   // When notifyCompleteAction is called, the lambda's 
   //  supplied as arguments to sendTo (because they close over params), will use the values
   //  set into params here, when the lambdas run
   {
    type: 'notifyCompleteAction',
    params: ({ context, event }) =>
      ({
        logger: context.logger,
        sendToTargetActorRef: context.parent,
        eventCausingTheTransitionIntoOuterDoneState: event,
      }) as INotifyCompleteActionParameters,
    },
  ],
},
/*...*/
)
flint torrent