Join egghead, unlock knowledge.

Want more egghead?

This lesson is for members. Join us? Get access to all 3,000+ tutorials + a community with expert developers around the world.

Unlock This Lesson
1×
Become a member
to unlock all features

Level Up!

Access all courses & lessons on egghead today and lock-in your price for life.

Autoplay

    How Action Order Affects Assigns to Context in a XState Machine

    xstateXState
    >=4.6.7
    javascriptJavaScript

    While the order of actions in XState is fairly clear, how assigns are handled in them is non-obvious.

    If you have a scenario where you try and utilize context in one action, then assign a new value to context, and then try and utilize the new context in another action, you'll find that actually both actions received the new context as their argument. Why does this happen?

    This happens because XState.Machine.transition is a pure function. In order to remain pure, it does not run the actions, it accumulates them into an actions array that is returned in the next state object. Since transition does not run any side effects, it must calculate the next context object and return this on the state object as well. Thus, any action returned is then called in the interpreter with the next context, not the context assumed to exist at the time and order the action was written.

    Code

    Code

    Become a Member to view code

    You must be a Pro Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson
    orLog In
    Discuss

    Discuss

    Transcript

    Transcript

    Instructor: Here I have a contrived example double counter machine to demonstrate how action order affects assigns in context. This machine only has one state idle, and a response to one event, incrementCountTwice. This event fires off four actions. One console log before to show the count, two calls of increment count, and one console log after to show the count.

    We scroll down here we can see what the incrementCount function is, it's an assigned function to Context, that takes our Context and gets the current count and adds 1. Let's call this and see what happens. Opening up the console, we see that we actually got before 2 and after 2. That's odd, why did that happen?

    To understand this we actually have to think about the machine transition method. I'm going to write some pseudocode up here to help it make sense. Machine.transition is a pure function. It's a function of the state and the event. In order for this to be pure function, we have to get back the same object as our next state every time we pass in this particular state and this particular event.

    The way it does this, is it returns the next context completely, but taking all the actions, the state's exit actions, the transition actions, and the next state's entry actions, and filtering out any assigns that might happen in them, and merging them into the next context object. It looks like this. Since all the assigns are batched together to give us that next context object, all we're left with are any actions that aren't assigns, so it's almost as if these actions are ordered in this way.

    All the assigns first, and then any of the other actions in the order that they were declared. Knowing this, we can remove the pseudocode and we can make a change to how our double counter machine works to actually work as we expect. What we realize is we actually have two kinds of contexts, we not only have a count, we have a previous count.

    Since we have a previous count, it makes sense that we make an action that assigns this value during this. We have incrementCount, we can also have setPreviousCount. We can take this, and add this to our actions. Now that I've added that, I can update this to previousCount, save the machine, and call increment twice. I should be able to open the console, and we now see a before of 0and an after of 2.