xstate: Unable to send event from parent to child

Bug or feature request?

bug

Description:

When attempting to send an event to an invoked child machine, the event is not sent and there is an error Error: Unable to send event to child 'pong' from service 'ping'.. There is also this warning: No service found for invocation 'ping.active:invocation[0]' in machine 'ping'.

(Bug) Expected result:

able to send event from parent to child (and vice-versa)

(Bug) Actual result:

unable to send event from parent to child (and perhaps vice-versa - untested)

(Bug) Potential fix:

There seems to be some sort of name-spacing imposed within the send function that maybe not reflect the addressing the parent machine expects. I’ll look at the code later today and post more information about a potential fix. I wanted to raise awareness of this issue as soon as possible, however.

Link to reproduction or proof-of-concept:

https://codesandbox.io/s/p57408nyx0 (copy-and-pasted the example from the documentation)

Update: I just reverted to 4.3.0, and then to 4.2.4, and am still seeing the same issue. The only difference seems to be in 4.2.4, the service is identified by a seemingly random number instead of the id. For all versions, I also tried creating a service for the child (which matches the use case I have in my application, where I need a service for each child machine for isolation in support of my React component structure).

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 19 (11 by maintainers)

Most upvoted comments

In my case, I could not see the received events in the child machine because I was using async/await in the invoked callback. I know the docs say:

Callbacks cannot use async/await syntax because it automatically wraps the return value in a Promise.

… but since everything else in the src’s body was running fine, I assumed it was not the issue. Anyways, I resolved it by refactoring my code to remove async/await.

It might be useful to open a new issue - XState has changed a lot in 3 years

This is expected not to work, because XState doesn’t magically restart the service for you, nor should it - imagine if you invoked some POST request that you only want invoked at most once; it would be wrong and error-prone for XState to “re-invoke” every service.

Instead, what you should do is persist events and replay those events. Here’s a rough idea of how you can do that:

const events = JSON.parse(localStorage.getItem(...));

const [state, send, service] = useMachine(someMachine);

useEffect(() => {
  // replay events
  events.forEach(event => { send(event) });
}, []);

useEffect(() => {
  const sub = service.subscribe(state => {
    // persist each event to localStorage
    // exercise left to reader
    persistedEvents.push(event);
    localStorage.setItem(...);
  });

  return sub.unsubscribe;
}, [service]);

In general, use an event-sourcing pattern instead of state rehydration if you want to re-invoke services.

@tmikeschu Can you prepare a reproducible code example?

@davidkpiano it looks like the https://github.com/davidkpiano/xstate/issues/351#issuecomment-461110580 is no longer functioning code. Can we revisit this? I hit this when trying to invoke a service on a rehydrated state.