State Modeling in React with XState Parameterizing Actions Solution
Transcript from the "Parameterizing Actions Solution" Lesson
>> Let's go over parameterizing actions to to complete this exercise. What I wanna do first is I want to actually make this tick events work. So this is just basic React material, but we are going to be going over using an effect to send an event to a machine.
[00:00:23] So if we have useEffect over here, we want to basically send a tick event on every interval. So let's just leave this here for now. So we have a setInterval. And on every interval in this case, it's going to be 1 second times whatever that interval is. So if the interval is 0.1 which it is, that's going to be 100 milliseconds or one 10th of a second.
[00:00:55] So we're going to send a tick event every single time that happens. Of course, we want to take care to clean up the intervals, so const interval = setInterval. And oops, we'll just call this I, and then we return a function that clears that interval. And so this is our cleanup function.
[00:01:22] So this is going to send a tick to that machine. And that tick should be handled by incrementing the elapsed time. So we'll say on TICK, we don't change the state, we still want it to be running. So again, we're not adding a target, we're just going to add an assign action.
[00:01:45] And we're going to be changing the elapsed property. And we have a function that takes both the context and the events. And so we are going to be returning the context that elapsed plus the context.interval. Remember, all we're sending is the tick events, that event has no payload, so we don't even really need it over here.
[00:02:11] Let's see if that works. So if we go back here, reload and play, you're gonna see that the time is going down. Now, the way I coded it is, even though it's going down only by one second because we're doing a math.floor function, you can see over here that it is actually updating here every tenth of a second.
[00:02:36] So we know that that logic works. If we press play, it'll do that, and we could reset it. So the other part of this is parameterizing these assign actions. So again, this just makes it more clear to understand what's going on. So we could say constant reset equals that assign action.
[00:02:58] And then we could do reset over here. We could move this to tick. So actions: tick, and we could also move this to add minutes. And then that's just addMinute. And as you could see, everything remains exactly the same. But we have our actions parameterized. So that gives us a lot more flexibility in what we decide to do with those actions.
[00:03:41] What is the difference between defining them here and defining them in actions? In reality, there is little difference, but when we parametrize them, so let's call this reset as a string. And we put reset over here. Now, this actually becomes, sorry, we have to add actions, reset, reset.
[00:04:10] Now this becomes available as an action that you could use to change over here, so you could say, actions reset, and then do something else. So by default, if this is a function, then that function has a function name. So if reset was a function, then it will automatically take that for you and you could also parameterize it as well.
[00:04:43] Again, it's better to be explicit. So you could just have those over there. So in short, if you intend to be flexible with those actions, then I do recommend putting them in that actions so that they could be read up here. So you're absolutely correct. This, all of these could be, parameterized right over here.
[00:05:10] And this one as well. And you're going to see that this works exactly the same. So we have the tick working, have everything else working, yeah. But in general, it's good practice. Move them to the top over here to make it more clear. And then to make it more flexible, move them to the second argument which takes those actions and allows you to change them.
[00:05:45] Any other questions?
>> I haven't done a lot with testing, but I was under the impression that having the options, having parameterize like that using options is very helpful with testing.
>> All right, so the question was about testing and using parameterized actions. Yes, testing is where it's definitely going to be the most useful and that's because sometimes actions can do side effects.
[00:06:10] And in fact, that's exactly what actions are for, and sometimes we don't exactly want to do that. So we're going to be seeing that in future lessons when we actually remove this use effect and have an actual tick there. But yeah, we could definitely just specify, what we want to do there instead.
[00:06:36] Right now, the actions that we have are just built in xstate actions. But actions could of course be functions that are firing forgets. They don't do anything with the current state of the machine. They do their own thing and machine doesn't care about them. So yeah, definitely in a testing scenario you do you want to parameterize your actions so that, for example in here, you could either make your actions do no ops, which means, not doing anything, or you could make them do something controlled in the test environment.
[00:07:12] So yeah, that's a very good point.
>> All actions are run asynchronously, right?
>> So the question was about the order of actions being run in general. Here's what happens, when useMachine takes a machine. It creates a service, and that service is an interpreted machine. I go more in detail about that in the first workshop.
[00:07:39] But that service it receives an event, and then it's going to do these two things in order. First, it's going to calculate what the next state should be and that's synchronous. So for example, if we are in the idle state, and we do the toggle events, it's gonna go to the running state.
[00:08:00] And that running state is going to have state.actions which represent which actions should be executed. Those actions are executed immediately after the state's transitions. So they're not quote unquote asynchronous but you should consider them as basically all occurring at the same time. In general with state machines, asynchrony is not really a thing because the idea of waiting or waiting something is itself a state.
[00:08:34] So you could just describe all of those things as separate states. But yeah, in general, just think of actions as fire and forget as you don't know when they're going to execute. But in general, they execute right after the state transition. So it is sort of synchronous, but don't rely on that.
[00:08:52] And the reason you shouldn't rely on that is because actions are firing forgets. And this is on the forgets part.