Invoke an XState Service when Entering a State

Isaac Mann
InstructorIsaac Mann
Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 3 years ago

It can be tedious to create a paired success and failure event for each external action that a state machine triggers. Instead xstate can integrate directly with a promise and respond to the resolve or reject status of the promise itself.

Instructor: [0:00] Let's reuse this state machine to fetch planets as well as people. Changes name to fetchPeople state, fetchPlanet state. Let's change the network call down here to fetch planets instead of people. Now we'll duplicate the rendered HTML. Let's copy this. We'll update the person references to planet. Now we have two buttons. The top list loads people, and the bottom list loads planets.

[0:33] It's great to be able to reuse this fetch machine logic, but every time a component uses this fetch machine, they have to remember to send a resolve event and send a reject event when the network call returns. If this logic will happen every single time, it would be better if it was inside the machine itself.

[0:53] We can do this by having the pending state invoke a service. We'll add the invoke key. We'll add the invoke key and give it an object that describes the service.

[1:03] A service has a source property in which we can define a service directly with a callback or a promise or we can give it a name for the service and allow the component to define the service itself. Then we can add an onDone transition, which will just be this resolve transition and an onError transition, which we will define as the reject transition. Now we don't need this action or these transitions.

[1:29] The onDone and onError events are generated automatically for us by X state. They have their values put on a data property. We need to update our actions to look at that property. Fetch data is no longer an action, it's a service.

[1:47] When we use this machine, we'll put fetch data under the services key and this service can return a promise and observable or even another machine. In our case, we'll return a promise and we no longer need to send these events to the machine because the onDone and onError transitions take care of this for us.

[2:07] We'll do the same thing for the planet machine. We can shorten this. We'll update this one to the shorter version. Reusing this fetch machine is a lot simpler. All you worry about are the pieces that change the network call and then deciding how to render the result. Let's take a look at the app and you see that it's working correctly.

[2:30] When we view this state machine in the visualizer it looks very similar, except instead of having an entry action on this pending state, we see that it's invoking the service of fetch data. Then our done action is associated with the fetch data service and the error action is associated with the fetch data service.

[2:50] When we fetch, we go into pending. The done action takes us to successful and the error action takes us to fail.

Sébastien BARRE
Sébastien BARRE
~ 3 years ago

Thanks for this series. There is a typo here. Once you convert fetchData from an action to a service, it should then be relocated to the services: property in the machine options in App.tsx, instead of the previous actions: property.

Lucas Minter
Lucas Minter
~ 3 years ago

Hey Sébastien! You are correct. I went ahead and got those errors in the transcripts fixed.

Markdown supported.
Become a member to join the discussionEnroll Today