JavaScript Marathon | XState Fundamentals with David Khourshid, Founder of Stately

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to javascript marathon a full week of free online courses in some of the leading web development technologies and concepts today's trainer is david corside founder of stately and creator of xstate presenting xstate fundamentals if you have any questions after today feel free to follow david at davidkpiano on twitter a special thanks to this week's sponsor this.labs offering personalized training programs to suit your organizational needs ensuring you and your company stay on the leading edge if you find keeping up with constantly evolving technology is a struggle and want to bring your team up to speed on one of the latest technologies contact us today at hi this dot dot co to set up your complimentary needs assessment this.labs is hiring we are hiring engineer managers and senior software engineers if you are interested send us your info at jobs this dot dot co we're winding down the year we do have a couple more events for the rest of 2021 state of react happens on december 2nd graphql contributor days on december 7th state of angular ecosystem on december 9th and our monthly mentoring happens on december 15th we also have two more stops on our angular and react world tours the angular world tour stops in tokyo on december 1st and the react world tour stops in mountain view california on december 1st as well and finally javascript marathon is wrapping up for the year this week but we are going to be back in 2022 march 14th to 18th and stay tuned to see what those sessions look like and with that i will turn it over to david hi everybody and welcome to javascript marathon today we have a very special guest david who is going to be uh teaching us all the awesome amazing things uh for those of you who don't know david uh oh my gosh david i remember when you first started x day then the whole the whole world started screaming about state machines and it being so awesome and i think education on this is so important and um you have a lot of other stuff going on so if you want to do a quick intro and then we can just get straight into the training sure so uh yeah my name is david i've been a developer for about 10 years i um i was at microsoft actually for the last four years but i've been working on this open source project called xstate for the last six years and eventually there was a point where i realized that i needed to work on this and related tooling full-time because um just the idea of software modeling is so important in our everyday developments but there aren't really that many good tools for that and so this is something that i really want to solve with the tools that we're creating over at stately so um i'm the founder of stately and there's a whole bunch of awesome uh developers working for us um and we're making some really really cool things one of the things we just released is actually this visualizer which allows you to create state machines and we're going to talk a little bit about that i'm sort of jumping ahead right now but like you could say initial loading states and then give states and i know that this is tiny i just want to show you in general what this is loading success so you could like define your states and then you could say on [Music] loaded success and so this visualizer allows you to create these state machines really easily but again this is me fast forwarding so i really want to instead start at a blank slate and if at any time anyone has questions in the live chat over here please just raise your hand because i really want this to become an open discussion and so um typically uh when we talk about like state and software modeling and state machines and especially x dates uh the library i created which is a library for state machines and state charts one of the biggest questions becomes why would you even reach out for a library like this there's umpteen different state management libraries and you know it it could be hard to choose one and hard to see like what's the differences between like you know what each state management library does and how it's going to you know help me accomplish my goals in my app um and so where do i even start if i want to get started with state machines um and so before we get into that i i want to just talk about just being able to model your application logic visually from very first principles even if you have no idea what a state machine is that's where we're going to start a completely blank slate um so and i'm going to be using excalidraw for now to do this but eventually we'll have a visual editor that makes it a lot easier to create state machines so imagine that i have a really simple media player app that i need to build and it has a few features it has the current elapsed time it has a you know thumbs up thumbs down if you don't like the song you could press play or press press play press pause try saying that five times fast or you could click skip in order to skip to the next song so it's a very basic media player and if you happen to have a tesla model 3 or any of the teslas then you'll recognize this immediately except without all the colors um but that's sort of what i modeled that off of again it's a really simple interface and um this is probably something that is about the level of complexity that you might encounter in normal apps so when we think about state modeling we're really thinking about how do we model complex application logic that might start off simple but might get complex later and how do we build uh to um just to make those kinds of future changes a lot easier so the question becomes you know where do we even start uh so the first thing that i would say that you would start from is um think about everything that can happen in the app so i'm just going to label this as uh oh i need to zoom in a bit there we go we're gonna label this as events you know we have a bunch of events and these events are things that can happen if you're coming from redux or ngrx or ux these might be called actions but the the formal term i guess a mathematically correct term i mean there's many different terms for these signals messages events uh but we're going to be calling them events because these are describing things that happened so what can we do in the media player app well the user can play so you know just press the play button the user can also pause and let me zoom in oops zoom in a bit here um so it's good to think about like what else can they do wow 500 ooh this goes slow uh okay whatever that's fine um so they could also skip ahead to the next song um they could also fave which is you know giving it a thumbs up they could unfavor it and so these are just the things that a user can do let's see if we got everything save on save play pause and skip ahead and so now we have a good idea of you know what things can change the states of our small application but these aren't the only things that you should consider in terms of events too because these are just what comes in externally from the user however there could be other events too that you need to think about and so the best way to think about it is just envision how this media player works and what changes so even though we could press play press pause we have this timer over here which shows the elapsed time of the song and so um when the when the music's playing it's going to go down so that state is changing it goes down from like 123 to 122 to 121 and so one important concept that you have to keep in mind with state machines and pretty much all of programming is that when the states change happens there is always a reason for it and these reasons can be described via events and so um i would just say like i'm just going to call this a a tick so a tick like a ticking clock a this would represent the internal audio player saying hey this much time elapsed and so it would um you know a tick would just say or actually we would you know call this like uh a lap so in events coming from the audio player saying okay now there's one minute left um you know now there's half a minute left etc and so those are those are external events um and i'm going to color this differently just to show that you know this is external this is that's too close of a color so is that all right we'll do that um this is internal now these events you you pretty much treat them the same uh when it comes to stay machines so we have all of our events and you know some of you might try to skip ahead and think okay well now we have the events what are the states and so i would actually say don't think about the states yet um finite states are more of an emergence property than something that you have to think about upfront so this would definitely be a good place to start so um in thinking about how all of this works uh you know we have all these events happening and um those events are going to change the state uh so typically what you might do is you might have some sort of is playing variable um you know is liked is unliked and just all of these boolean values and so what we want to do is translate those boolean values to um to just finite states and so uh yeah this is where you know we sort of get into x date so um yeah just to introduce the api to you and actually i'm going to stop there and pause for any questions if anyone has any questions on what we've done so far to just like think about the events and how we would model uh this sample media player application anyone's questions you could jump in so um just a little question about this and i noticed that i have been doing this for other frameworks like you say reducing your ex so basically what you're trying to accomplish is to have a an overall idea of all the events that um happens or they're yeah can occur at some given point the application um and the different actors that can uh interact with it and and use that as the guiding force of your architecture yeah exactly and so it all starts from the events um so yeah i'm just gonna put states here uh so yeah your your intuition is exactly correct there you're you're basically collecting all of the lego pieces that sort of um you're gonna bring together and use to construct uh the rest of your application logic um yeah so uh when we think about states and i'm gonna you know just make this white uh like i said we have some uh zoom out a little bit we we usually use booleans at least when we're first starting out um and so that's fine so start off with that if you're used to that and you might you know have something like is playing uh true right and then you know eventually that boolean might become is playing false and so if you're starting off with the media player you might you know use this but you have to ask yourself two things first of all what can cause this boolean value to change and so the answer is um that's the wrong line but yeah there we go the answer is that um if you press pause so i'm just going to put a pause event here oops pause then it goes from is playing to false um however if we play then that is playing becomes true so i'm just going to put this up like that and so that's how these can change between each other and typically when you have a boolean value or any sort of value that represents a mode or a state well then that can be considered a finite state um also there's a difference between finite states and infinite states so um infinite state would just be data like how many seconds have elapsed whether it's liked or unlikes like those aren't really different states even though it is a bullying it's just something that's qualitative or sorry quantitative not qualitative um and so uh yeah with finite states you actually wants to think about the behavior and so what is a behavior a behavior is something that says when i'm in this mode or this behavior only these things can happen and so if i'm in a different behavior different things can happen so for example um is playing true like let's say that we're currently playing if the user were to press play again like let's say that there was another button for play then it's like we're already playing so nothing should happen we're not going to tell the audio to start the song because uh or the media player to start the song because the song's already playing same thing if it's paused if the user keeps pressing pause like if it were a separate button like in older car interfaces then um nothing should happen it should ignore those events and so that's a difference in behavior the analogy i like to make is it's sort of like um as a human you know you're either asleep or awake you can't be both asleep and awake at the same time and you behave differently when you're asleep rather than when you're awake when you're awake you're attentive you know if things are happening like something's on tv you might be responding to that um but if you're asleep you're going to respond differently or not at all to uh to many events so um these booleans are going to be a good way of like um indicating that uh something should be a uh a finite state rather than um you know just data well that shrink for no reason all right there we go and so now we could just convert these instead of being booleans we uh these are really good candidates for converting uh to finite states and so let's do that and so step one is to consider what is your initial state uh so when you first get in the um you know in here i'm going to assume that it's paused because it's like we don't know if you want to play yet so i'm just going to say you know paused is our initial state and then we're going to copy this over and say playing so now depending on what happens you know of course we have a pause event and we have a play event and you know there's other things that can happen too but we're just going to be focusing on those two for now so a play event when you're in the playing states remember this is a behavior it's going to take you to the past state which is a different behavior and so same thing if you're in the apostate and you go to the playing states uh you know or if you're in the apostate in the uh oops that's the wrong way okay we'll just switch it like that all right so if you're playing pause event happens now you're in the past stage if you're in the past eight play event happens now you're in the playing state and additionally we would have a an initial state so i'm just going to copy these over here and this is how an initial state is um you know is denoted so we have a little dot with an arrow that says hey this is where the machine should end up at first and so this becomes a very basic uh a basic state machine and so you might be thinking like okay we moved from using booleans to now using um you know using just two separate states and you might be thinking okay well that's a little bit annoying like why why can't we just use booleans like there's two states um well especially with like a car audio interface the problem with using only two states is there might not just be two states for example if a song is loading we need some way of representing that and so we're not going to do it in this application but just for example sake uh we're going to say you know there might be a loading state and so if we're playing or if we're in the past states then something might happen that might cause us to go to this loading state right so um you know whether we're in pause or playing uh yeah i'm just gonna copy this there so we'll just call this buffering or something well whatever the audio player tells us is happening and so when we're in this loading state um at least in the car interface this turns into a spinner so you can't play or pause um and so you know now we could just go back from loading to playing or to pause depending on um you know where you were uh so that's why like introducing new states becomes a lot easier when you uh when you use it or when you use finite states rather than when you use booleans because remember booleans can only represent two values and um with finite states you could represent a lot more values um of course a finite number of values that way so i'm just going to get rid of this loading state for simplicity and um yeah so just some technical terminology just to review we have the initial state which is paused we have another state which is playing and um when the play event happens again by the user we transition from pause to playing and so when we're in the playing state and the pause event happens we transition from playing to pause and this is called a transition so this arrow we have an event here and the events is you know the event of the transition and the transition says we're going between these two states when that happens um also it like it doesn't really um it's not really necessary to change states when you are actually this should be over here sorry trying to draw and talk at the same time um but it's not necessary to uh change states when you have an event so uh for example we could have an event that go back here and bring this to back okay so we could have an event like uh fave and i'm just going to put this in here and so this fave event can it basically doesn't need to change state so it's just like you know in an invisible transition that that only does an action and so uh that's something that we're going to talk about too so faith shouldn't really change any of these states but it should do something and same thing with uh with unfave that should do something as well um but before we go too far into this uh we're and you know gonna go back to x date i wanted to pause for any questions um here so far like just in modeling this i mean so far it's a basic state machine but it's going to get more complex all right no questions you must just be like the best teacher ever i guess or yeah maybe maybe this is really basic stuff which you know if if all of you did your homework ahead of time and learned this then great um all right so uh let's actually get into x data and see what it's all about this is a react app and uh we're actually not going to be touching the react part of it yet i just want to focus on the machine part and uh if you want me to zoom in i could probably zoom in a little bit more just so that everyone can see and yeah we still have everything visible here i wish that i could hide this can i nope oh yeah i can there we go okay cool so um the way we create a machine with xstate and of course you could npm install xdate all the installation instructions are available if you go to xc.js.org docs or the github page then uh there's a bunch of templates for you to get started quickly uh depending on which framework you're using or if you're not using a framework that's completely fine too you could use xdate without a framework and google's talking to me because it's a faulty state machine so uh yeah there's also instructions installation instructions in the github just npm install x date pretty straightforward um yeah so let's actually create this machine that we were talking about um so you would use create machine and then you would add an object now in this object by the way by far the simplest way to start with a state machine is to have a single state and uh this state um is actually implicit so it's like the default route state of the machine and it looks exactly as you're seeing right now there's nothing in this object it's completely empty um but we could add on and then we could start to add events that might happen so uh we could say and just for convention's sake and you don't have to do this but i'm going to uppercase all the events just so that you could easily see the difference between them so you know we could have fave we could have unfave we could have play pause and skip and so these are going to be all of our events in the machine and these could all do stuff uh so the place that we hold like the extra state the states that that's not our finite state is in context so you could think of it as like contextual data for like specific to the state machine um and so uh you know we might have a duration let's say that it's uh i don't know 300 seconds long which is what five minutes and elapsed uh so far nothing elapsed and so that's going to be for the time over there and uh of course we have a boolean for um babed and this is going to be false and um yeah so uh where we're not really going to be doing the skip song thing we're going to be focusing on uh play and pause and you know just for um you know starting off we're going to actually add that uh that smelly boolean is playing and we're going to make it false so this if you've used redux or vux or ngrx this is going to feel just like a reducer except it gives you this nice little structure of um you have your data over here you have your events over here so you don't have to write any of those uh annoying switch statements and everything that happens happens in here so uh just just to try it out um [Music] oh yeah so this is a transition object and so in the transition object you could have a target which is like which state it goes to but we're not going to any state for this one and you could have actions that say which actions are to be performed when that transition occurs um so we're also going to pull a sign from xdate which is an action creator that you know allows you to modify this context and so we're just going to say fade true um and this is react specific but if you're not using reacts then it's also very similar in vue and i think in uh with any of the adapters uh the only important thing is um you know the the machine the machine is completely framework agnostic so you don't have to uh really worry about that um so we're going to hook up our machine to that uh that fave so i'm just going to find this one okay so this thumbs up uh the used machine hook actually comes from x8 react so you could just pull it from there and it's going to provide you two things very similar to use reducer it's going to provide you the state of the machine the overall state and send and so send is like dispatch if you're used to use reducer or redux same thing so we're just going to send an event object with type of faith and so uh this is going to console log the states i want to log the context just to show you what's going on inside okay so we have all of our expected data 300 elapsed faves false is playing false when we click plus now it says fade true so we know that that's working and you could just um you know copy and paste this here we want to assign fade to false [Music] and so this also highlights that everything is done via events oh of course we didn't hook that up so let's hook it up uh this is going to be unfaith so essentially you could treat x-state just like you treated every other state machine uh or sorry state management library before in the past um you have your actions and so you could just assign and that's going to change context and so already it works exactly the same way as redux and related libraries but one of the reasons that you would use xdate is to actually like orchestrate the different behaviors of your application and so that's where this is playing comes in of course we could do um is playing true is playing false over here you know so if i just oops i just added these here action so is playing this is going to be true and we would say is playing false you know that that might work um so obviously we have to add that too uh let me do that real quick so uh play and also um this is gonna be skip so we have play uh skip and so i forgot the pause button so let me add that real quick this is like one of those cooking shows where it's like by the way i have a prepared uh cake in the oven except no cake exists everything here is being done just from scratch so uh i'm just going to have a pause button over there cool so it says is playing true you can see that over there if i press pause uh it's playing true because i forgot to do this so true false nothing really that impressive right now however from what we modeled in our uh scale jar over here um these playing and pause states are really different behaviors and we're going to want to separate that uh so that we could better orchestrate like i said what happens when our app is in each one of those behaviors um so let's go ahead and do that uh where we first have to define an initial state and so our initial state is going to be like we said paused and then we have an object that represents all of the states by key so we have a paused state and we have a playing state and now we want to go between those states so we're going to get rid of this boolean because we're replacing it with these finite states and uh yeah so i'm just going to get rid of that and so when i'm in the positive state and the play event happens now i want to go to the playing state so instead of logging the state.context we're now going to log the state.value just to see how that changes and remember i didn't change the ui at all all these are just sending the exact same events so if i press play now we're in the playing state we didn't hook up the pause event yet so uh let's go ahead and do that now if we were doing a workshop i'd tell you all to do it but uh that's okay so um pause but by the way just fyi i think there were some some a few questions whenever you're ready for them yeah yeah absolutely so uh let me just make sure uh all right so we're in playing oh yeah sorry i have to on pause target paused okay cool so pause playing pause playing pause you know not too interesting yet we're going to see when we actually start to add you know add interactivity how this is important but i'm going to pause there for questions i think one of the questions was uh well can we use x-state outside the react component uh yes absolutely you could use x-state uh pretty much anywhere and actually let me demonstrate that for you real quick i i sort of jumped ahead and went straight into uh reacts but um yeah i want to show you how this could basically be used outside and there's really two ways first you could use that machine that we created and we called it media machine just for reference you could use that as a pure function and so this is how uh if i say um so const next date equals uh mediamachine dot transition this is going to be a pure function and it takes two expected arguments which is the state um and of course you'd have to recreate that whole big state object but i'm just going to put undefined and this means the initial state and then the event so we're going to say type play so if i console.log nextdate.value then oops value then you're going to see that it's playing and so now i guess i'll call this uh next next state we're going to take that next date i'm going to send it well actually let's see what happens when i send it the same events obviously nothing is going to change you know it's going to go playing playing but now if i send it the pause event it's going to go uh oh next next date value it's going to go from playing to paused um and so instead of using value if you see the entire state object then you get a lot of things in here so let me just point out the important things the first one is the value and so this is the finite state value so this would be right now either playing or paused the context which is all of that data that extra data that we have and uh other things that might be useful are um events so you have the actual events object that you sense to the machine right in that state object too in case you want to do anything else with that and there's a few other useful properties that we're going to take a look at soon but uh for the most part only these two are the ones that you really need to care about in most applications the value and the context um but yeah so the second way uh to interact with this outside of react or any framework is by interpreting it and making it like a live object that you could send events to so we're going to call this media service equals interpret and we're going to import that from xstate you give it the machine so the media machine and also on transition i want to listen for the states so i'm going to console.log state.value and you have to start it because it doesn't start immediately and it waits for your permission to do so so now if i uh if i see this you're going to see that it's going to log pause because it starts the machine and says okay here's the initial state if i send the uh media service in event so send uh type pause or well it's right so play then uh it's going to log that it's playing so yeah those are the two ways that you could use it outside of react and hopefully that answered that question and then uh another question was how do we derive state um [Music] so what is meant by deriving state if you want to clarify um yeah i was thinking something similar to what selector stores in ngrx where you have the whole state but maybe you don't want to pass it completely to a component or you don't want or you want uh something built upon that passed to a component so how could be the recommended way of transforming that state to use it in other place of the application without having to uh transform that every time oh okay so um are binding tunes are using react or just in general are you talking about um just in general but react wars okay okay yeah so uh react specifically um there's there's two way or not two ways but there's uh two hooks that you would use for this so remember that service i created i'm gonna uh copy this out if you want just the service so service equals use interpret media machine this use interpret hook is only going to return the service and so that service can be subscribed to um and it's only ever going to render once so it's not going to cause any re-renders when the state changes no matter how often it changes um and so the way that you could select a value uh let's say that we want to um have a is is playing like going back to those uh those booleans but this time it's derived so it's okay um we would use a u selector hook and so this u selector takes that service uh [Music] and then we would just say uh state dot you know you could say state dot value equals playing or you could also do state.matches playing and that's sort of a built-in method over there so i'm going to console.log is playing and show you like this is just a small example of a uh you know of a derived value oh and it says send is not defined thankfully we could just uh grab that from service so i could say consent equal service dot send uh so yeah you see is playing true is playing false and now this is only going to re-render if um you know it is playing uh changes so whatever we calculate in here so if you've used redux before it's very similar the only difference is you have to pass that uh you know that service into there and so that's in the uh react stocks so otherwise if you wanted to just you know figure out how to select values outside of it um this for example in angular or something else um this service is subscribable so you could say media service dot subscribe so it is subscribable it adheres to that so if you want to map values in rxjs or whatever you get the state over here and you could transform those so i imagine with rxjs you would pipe it through um and then you know distinct until changed or something like that and uh yeah so any any selector solution that works with you know something that's subscribable is going to work the exact same way in short you get the state here and then you can respond to that state and say only do this if this part of the states uh changed so um yeah the u selector hook is available in react and the view libraries um and yeah so hopefully that answers your question um as far as making it making general selectors it's still something that we're thinking about like having computed or derived values directly in the machine uh that still we we want to make sure that we design that right so likely that might be a version five thing but it will definitely be a cool addition so awesome thank you one of my other favorite questions is how good is rxjs integration oh yeah so um people have been what's funny is we built adapters for uh reacts we built adapters for vue like just the hooks and you know the composition api stuff uh but for angular um we sort of didn't touch it we didn't make any adapters for it uh but part of the reason why is because well i don't know angular but the other part is that uh this does um it adheres to the tc39 subscribeable interface and everything like that so media service is already an observable you could plug it into rxjs it's going to work exactly the same and in fact in spelt uh if you have this media service you could just read the states from that so i think it's like something like state equals media service or however you do it in in spelt or yeah something like that because it is subscribable and it's going to work pretty well with uh any rxjs solution and then uh uh math or no matthew was just a comment chris do you want to ask her a question yeah so i was basically curious if the media service that you created in line 49 and the machine that you created in line 58 to other like the same instance and will if it will events in react app will be picked up by this media service and vice versa ah okay so no these are these are completely different and that that's a good point to talk about too the media machine is like a blueprint for your machine it's like hey if you were to create a live living version of it here's the blueprint of how it's going to work and so by doing interpret here this creates an instance of that and so use machine internally is also going to interpret the machine so this creates a completely new instance so they're they're completely separate from each other um but yeah if you did want to use the exact same instance then uh you would basically do like just any other like data passing solution for example in react you would use context in order to do that uh you know we could even i mean this sort of goes against the rules but we could say um like const is playing equals use selector and i'm grabbing this media service from the outside now media service uh state state.matches playing and so you're going to see that uh well if i log is playing now it's grabbing it from the outside and so we could also say cons or you know let's even do this from the outside too consent equals media service dot send um again i don't recommend doing this but it works and the the reason why is because it just becomes harder to test if you're not passing it in via props or context uh so it's gonna be a little bit of a nightmare to test but that goes for anything with react if you are using external values inside of your components but yeah so now that refers to this service and not the one that's created uh in here so thank you yep [Music] any other questions [Music] all right awesome so um let's actually make this do something um because okay we're going back and forth between playing and pause but like you know that that doesn't really show like you know the benefits of why you would use state machines and everything um so i i actually wants to talk about um effects effects are something that you know we typically uh push to the side and stay management we're like okay you know what this is great for just changing state and everything and then if we have to you know execute an effects um you know just throw it in middleware or in reacts throw it in a use effect or something but with x-state effects are first-class citizens um so uh you you could even like just um declaratively state which effects are supposed to run um inside the machine definition without actually providing the implementation for that but before we get there let's go back to our machine over here um you know we go back and forth between playing and paused and something i'd like to say is that effects are so important and should be first class because without effects your your app is useless it doesn't really do anything um so that's why we have a notation in state machine notation where you would say do and then you would just say what you're going to do so i'm just going to say start player and so this signifies that you know that's that's an effect that should be done i'm going to make that green and so in pause we should stop the player and so um you know now with that we're in the playing state remember that we also have that fave event so i'm actually going to stretch this out over here um and uh actually no that that favorite event is there so we don't really have to do anything there i i just want to show you that like we have these actions up here and um these actions occur on the transitions so basically when you go from paused to playing uh this darts player action is going to be executed and this is important because even though there isn't a transition uh for play on playing which i mean there shouldn't be like there's nothing should happen there i'm just going to add it anyway and so i'll show you that play we don't want to start the player if we're already playing and the user hits play you know a million times for no reason so um that's why we don't want to tie our side effects to you know the actual button and so what i mean by that is we don't want to do this sent i play start player like this is something that we typically do and even worse i've seen like you know we would have a uh fetch something that then do something else so basically all the effects are happening inside the event handlers and one of my favorite things to do when i see this is if it's a button and it's not being disabled or anything is just click that button multiple times and see what happens you're going to notice that the fetch calls are going to be called a lot you're going to get a lot of unwanted behavior and this is also exhibited in many apps in many different ways i'm sure you've been to an app where it says please do not reload or exit this screen otherwise bad things are going to happen um you know or please don't click this button more than once if you know you're submitting a payment um and i run into it even like as recently as this month where if you click a button too many times because you think the app is frozen it's going to have unwanted side effects so that's why it's good to visualize and manage these side effects in a declarative way um and so these are an example of like doing these effects in uh in these transition actions so um i'm going to go ahead and add those effects right now um so play target playing uh oh yeah so one thing to add too there's also three types or three places where you could put effects you could put effects on the um on the transition itself uh you could put effects on the entry of a state so i could say entry oops start player and notice how i'm just specifying it as a string or you could specify effects um whenever you leave the states so on exit stop player when you're modeling this i would always almost always recommend you start with putting it directly on the transition and the reason why is that let's say that you know you put it on the transition and you have another transition over here that comes from another state and you see like okay i also have to start the player here and if i copy this and and i have another transition now i need to also start the player here and you start to notice a pattern you see that every single transition that comes into the playing states starts the player it does that action so what you could do is you could dry things up and say okay instead of that i'm just going to have this be an entry action and so using entry and exit actions are basically a way of just cleaning that up so that you don't have to repeat yourself everywhere but for sake of simplicity we're going to put it on the transition actions first um so we have start player and uh i'm just going to put stop player on the other one so let me just find it actions stop player okay so we play it says no implementation found for uh start player and i think we're forgetting to oh yeah so let me get rid of this okay so play um you know it it's going to try to execute the start player action but if you don't have an implementation that's going to warn you and if i pause um you know we don't have an implementation for stop player either so uh yeah let's um you know just let's just make it sort of a dummy uh class for this so um let's call this uh like all right trying to figure out the best way to do this without getting into anything too advanced um [Music] all right so yeah we have start player and stop player and so that that can be some sort of external uh thing too um actually i'm just gonna put it in here for now so uh we're gonna use effect for here and just do it there and it's never going to change so um or actually should that be the best way to do it okay no i'm going to do it differently all right so we're yeah we're actually going to get into a little bit advanced material but it does show you like um you know what like just just what you could do um with x date so um i'm going to create an invocation so we're just going to say invoke and i'm going to give it an id of player and so what this is is it's basically something that does you know some sort of effect that lasts in this case for the entirety of the machine um so this player we could start stop it and so this player is going to actually control the playing of music um and everything else uh so let's see i'm just going to have a source over here and um in fact if none of this makes sense to you then that's fine just know that there's something else that's controlling um you know basically what's happening so send back [Music] receive just because there's no actually you know what i'm going to backtrack a little bit because i do want to keep it uh simple uh especially since we only have like half an hour left um so we're going to be doing this outside of the of reacts just to you know just to demonstrate uh yeah i think that's going to be a lot simpler so i'm just going to have a function start player and that's going to do something in the function stop layer and that's going to do something else so we're going to have let's interval id and of course there's no interval so on start player interval id equals start interval or um is it starting a rule oh said interval um and so yeah we're going to be doing something there and that's after every second and then uh over here we just uh i think it's clear interval yeah there we go clear interval interval id okay so um i'm just going to console.log uh tick uh and this is just so that you could visualize these actions happening okay so we have our media machine over there and uh we wants to provide these actions first so i'm just gonna say actions uh start player and stop player um okay so now you're going to know this and just to recap over here when we're playing um yeah so when we play that's going to run start player when we pause that's going to run stop players so if we play here uh yeah now you can see it's ticking every second i should probably just do like a date.now or something uh just that it shows in one second intervals just like that and so when we pause now you notice that there are no more text so when we play it's going to keep ticking when we pause you know same thing uh so i guess if you wanted to do this inside of your you know machine you might have like a separate media player clients that you're using um but you could also add those actions as a second argument over here so we could say actions dark layer stop layer and so now we don't really need these here because they're over there and so let's also console.log state.value and i also want to show you state.actions because uh this is why we have those declarative actions right now we're in the paused state and nothing is happening now when we play we see that there's one object in that array and it's a type star player it has an exec which is the implementation and so that's basically telling the interpreter that's what should happen um you know when we start playing and so same thing for paused uh when we click pause it's going to stop the player and so um you know the ticking is going to stop all right so um now how to actually feed that back in uh to the machine um you could do it either as an external event or you could handle that internally as well um and so that's uh yeah that's going to be a big topic for the next half hour but first i wanted to pause and see if there were any questions about um about the use of actions all right uh so no questions um and again something that i wanted to point out is that when you play uh you know let's say i keep playing play because i'm in the playstation i don't know if you can see but i'm clicking this button furiously and nothing bad is happening like we don't have the states changing um everything is working as normal you know even if i click paused a lot the state is only going to change once and this action is only going to execute once because we're following the arrow and we're executing this action um so yeah at this point we're going back and forth between this excalidra and this to sort of visualize you know just exactly what's happening uh but instead i wants to bring in um x8 inspect to show you that we could actually inspect these machines in real time so um yeah let me just do that real quick you would import inspect from xd inspect and then inspect i'm just going to say iframe false and we're going to use the new visualizer to do this so url uh stately.ai slash biz inspect these are going to be default options soon so you won't have to um type all of these at once but i put iframe false because if you have an i-frame it's going to show there if you don't it's going to open in a different window and so once you have that set up and you set uh dab tools to true check out what happens so i printed out event listener interesting let me reload okay let me uh maybe it doesn't like me for some reason gonna reload this if not let me just go to 0.401 let's see if i did anything wrong inspect i frame false hmm would this be full string or false bullet oh yeah how did that happen okay sorry about that okay so uh thank you for catching that by the way i would have never caught that um but yeah so now you have paws playing and these things are uh awkwardly there they should not be all the way up there but uh i think it's because i have a few things here we're going to comment this out for now so that's just a little number okay so um yeah we have play and we have pause and so if we play this you could see that it goes to this plane states and if we pause it you could see that it goes to the paused state um but what's cool too is that you could click playing over here or play over here and it's also going to go to the playing state and you can see that it's uh it's ticking away right over there um and yeah so you know you could go back and forth between these two um and use that to visualize your machine in real time um but yeah so that's using the inspector if you wanted to use that um but let's actually make this a little bit you know more interactive and i'm just going to uh disable the inspector for now just by commenting that out so that we can get back to it um but yeah that helps you visualize like what's going on in your app it also shows you like just what's going to happen just like our state machine over here what's going to happen when certain events uh you know cause transitions like which actions are going to happen uh and things like that um yeah any questions about that all right so um yeah let's get some more exciting stuff um when we're actually like working with uh this uh you might have the requirement that we want the pause button to show when we're playing we want the play button to show when we're paused and typically we would do a bunch of boolean logic um to be like if is playing or if is if not is playing then show this button etc um but really we wants to think about the intent of why we want to disable or hide or show certain things and so in the case of um in the case of pause we want to show this pause button when we can't play because obviously you can't play you have to pause same thing with the other one you can't pause you have to play um so thankfully there is a i'll add this here there is a state dot can method and so basically it says if you can um if you can't play then uh then show the play button so um state dot can pause show the pause button because it makes sense that if you're not able to do something then why show that button so now if we click play see it turns into the pause button if we click pause now it turns into the play button so what's great about this is that you could change your logic however you want here let's say that you want the play button to always work now that play button is always going to show because of that logic the state.can method is basically saying can this transition be taken like for example play in this state if we're in this state it can't so it's going to hide if we're in this state it can so it's going to show and so yeah that's one of the benefits of um of doing it that way all right so uh now i want to jump into something a little bit more advanced which is actually uh manipulating this um the context over here and also dealing with external services because likely you're not going to have all of your logic inside a single machine and you're going to have to interact with third-party things and so with xdate everything is an event so if you're communicating with a service you send it in events if they serve it or some service or some other third-party thing is communicating with you it's sending you an event and so internally we could invoke these um you know these different they're called actors which are things that you could send and receive messages from um and so i'm just going to call this uh player like this is the the media player that controls uh the time and everything and so we're going to give it a source and we're going to use what's called a a callback invocation so um with the source uh it takes two arguments which is the context this stuff over here and the events which is the events that um you know that was passed in when you um you know got to this invoke this evoke is on the machine itself though so you don't really need to um you know the event doesn't really matter in fact yeah all right so the context does matter um and so with this callback uh you have two um arguments you have send back and receive and so uh this this is actually really really flexible so if you want to just like spin something up quickly using send back and receive is the way to go now we're going to be using these uh start player and stop player functions so i'm just going to bring them up here um and so uh yeah actually instead of using star player and stop player uh we're going to be more methodical about this i'm going to have the interval id over here set interval and it's going to keep ticking and then i am going to uh return a cleanup function and so all we do here is clear that interval so clear interval interval id and actually um now that i think about it uh this invocation should only happen in the playing state because obviously if we're paused then we don't want this player to send us ticks so um now instead of those actions i'm just going to get rid of those we're going to see the difference between using an invocation which is this and using uh actions so now when we play you can see that the ticks still happen and that's because we're invoking this uh this actor which is setting this interval and so now when we get out of the state and we pause no more ticks happen okay so now how do we actually communicate that back to the machine well we can't assign or manipulate context directly from here we have to send it an event so instead of sending it console.log tick we're going to i'm going to use this first argument here and we're going to send back um [Music] type tick so now let's handle that over here we have pause but now we have tick as well so we're going to assume that each tick is a second and so whenever a tick event happens we're going to decrement this duration or actually we're going to increase the elapsed we still want that duration but we're going to increase the elapsed by one so actions assign and we're just modifying the elapsed property uh so um just like just like this function over here we get two events or sorry two arguments the context in the event um we want to return the or we're just going to return the uh context.elapsed plus one so now i'm going to uh log st value and state dot context dot elapsed just to see what happens so we press play you can see it's incrementing it's going one two three four five press pause now remember elapsed is five so when we play again now keeps counting up so then we just have to do a little bit of math here and actually show this um i'm going to grab console or const uh we're going to get the duration and elapsed from uh the state.context and so now we're just going to show duration minus elapsed and you could pretend like that's the uh song like how many minutes is left in the song or actually i don't think songs work that way i think it's like just you know x out of you know 300 i'm not sure just pretend it's counting down maybe this is just a fun funky media player and actually i'm going to do i have a little function that i copied from stack overflow format mss no idea what that stands for but i'm going to use it format mss and i think all this does is translate these seconds into like a minute second format okay cool so we press play and you can see it's going down so now we press pause it's paused at 454 and then we play again now it's 452 451 450 and yeah so um we avoided like adding all of those um you know extra actions and instead we have everything contained inside this invoked player which is only doing two things it's sending back a tick um and it's also uh just clearing that interval whenever we get out of the playing states um so any questions about that so far no no questions all right cool so i'm sorry sorry go ahead one uh what are your opinion on putting uh like an observable chain into an invocation function and returning a function that unsubscribes is that the valid use case yeah um in fact i don't have rxjs in here but if you really wanted to um it's as simple as this so you could say source and of course you get your contacts in event two and you just give it some observable and that's all you have to do it's going to take care of subscribing and unsubscribing and just listening to those values um but the the only caveat there is that you want each one of the values that it admits to be event objects so you would do like something like pipe and then map if i'm remembering this right so let's say that it's some sort of um number you would just convert that to type like uh type hey i don't know well whatever event type you want and then value n or something like that so that's what you would do with observables um and it works natively with x data as well so cool yeah yeah you could definitely do that trying to do kind of uh analogy here the inbox will work similar to the effects in ngrx effects uh yeah so i don't have too much experience with ndrx effects but um yeah so this yeah it basically runs while you're in this sorry not in that but in this playing state and so it you know exits when you're out of it so if that's similar to ngrx effects then um yeah uh also like a a uh react analogy this would be the same thing almost the same thing is if you were using effect and like you had the state dot value and you say if state dot value equals playing or sorry if state dot matches playing um then you know do the ticks over there and then if it doesn't then you know clean up um so that that would be pretty much the exact same thing except now it's built into the machine instead of you having to manage it elsewhere nice all right so if there are no more questions let's uh let's add a little bit more functionality to this uh what i want to add is uh the yeah while we have 15 minutes left and i'll do this real quick but i i want to add this skip functionality just to show you another reason why you would want to use state machines and state charts for modeling this type of behavior um you know with something as complex as a media player so um we're going to just say that when we skip ahead uh it's going to um change to a different song uh so i'm just going to just for simplicity we're going to change elapsed to zero so you're going to see this just shoot back up and so pretend that means we're going to a different song so let's see we have playing we have paused and we also want to implement skip so go ahead and do that um so when we skip we don't actually want to change the state so we're not going to have any sort of target here and remember this is on the root of the machine so all we want to do is assign um we're going to assign elapsed to zero and see what happens there so we play we press skip and so now it plays a new song and keep keep know that it's still playing so that's you know that's a default behavior if we pause and we skip you know it's still paused so and so yeah that that's how easily you could add a another um you know another event uh but something that i i thought was pretty interesting especially when playing around with this in the in the car interface um was that when you thumbs up a song and you're playing like okay it's it's fate um in fact we could probably uh yeah let's just make that clear so i'm just going to add some opacity over here so style equals opacity um and we have to pull that from date so so fade 0.5 or 1. and so we're going to do the same thing for this one right here if it's faded then one otherwise 0.5 and so now we're using that data to show um well obviously it shows like none of these are failed yet but if we clicked here then you know you could see that it's fade um etc so yeah that's just one way of using that data um but something else that i noticed too was that if you unfave it means you don't like the song which means you really don't want the song to keep playing so um what you could do if you want to add multiple actions i'm just going to make this into an array over here and uh i'm going to do the same like skip thing and i'm going to put it oops put it over here as well so now we have two actions happening and you you might assume like this might do something else like let's say that instead of just assigning uh we also want to um console.log skipping song so uh let's say we were playing and we press here it's gonna say skipping song like you might notice that you know if something shows up like a toast or something that could be an example of an effect but now you're like ah okay so i guess i have to copy and paste this over here too because if i unpave something like let's say i'm playing it and like i don't like the song go to a different song it also needs to skip the song we do have a lot of duplication here um so one of my uh actually favorite things to do is um and like little techniques that you could do in the state machine is you could say i want to send myself an event and basically tell myself what to do it's like giving yourself a to do um or like hey remind myself to do this in the future you know just like you would do or maybe that's something that only i do um but anyway uh what we could do is say instead of um instead of just like copying these actions we could raise an event and say skip so we're assigning fade to false but we're also sending the machine itself in events and so now it's going to do these actions it's going to send itself a skip event and so now that skip event is going to perform all of these actions too so let's see if that works press play i don't like this song so now i press here so it's going to reset do the skipping song um not the skipping song but it's going to skip the song and uh and yeah do all of that so you know we could do it again fave faving does everything that's expected and um and yeah so that's that's basically how you would model the media player um any questions before we sort of you know do an overview of everything we learned well this is excellent i love this thank you for this and i know we are not at the end but the question that i that i have uh is most about uh composition about the machine state so how come we because we don't wanna if the app is big enough we don't want a single machine handling every single state an action that could occur we want to split it but we might want inside that splitting to also communicate with some pieces of other places is that something that is feasible or or is more about designing the machine in a way that works that way yeah it's definitely feasible and we sort of got a taste of it today with invoke so invoke creates a new actor and so in here we're using a callback actor but it could really be anything you could even spawn another machine which will also spawn other machines um and you could even spawn in a sign even though it's a bit uh more advanced but like with more complex app logic you'll see that that's actually really useful and so the idea is that if i zoom out a little bit you might have one parent machine which is here and that might spawn some other machines over here remember like either using invoke or spawn and so now these machines can talk to the parents or the parents can talk to those machines and if this machine wants to send in events to here uh there's there's a couple ways of doing this we could either uh tell the parents uh just like if you were to talk to your friends and you don't know this friend you don't have their phone number or something but you have a mutual friend you would ask your mutual friend hey can you tell this friend this um and so that event would just go like that or what you could do is uh this parent can give you a reference via a message uh to to that friend so i'm just gonna make this small just for yeah so we we could say uh hey yeah here's here's an eye i guess i can't change that um but yeah so um as long as you have reference to uh any of these you know what are called actors um then you could communicate with them and so actors can spawn actors and typically the communication is hierarchical but if you again if you have reference to them you could talk to them and this becomes really useful in uh big complex applications where you might have many different parts needing to talk to each other and it's also one of the biggest differences between redux because with redux it's like having only one of these but that sort of encompasses all of the logic in that combined reducers and with here you could have a mix of local and global and shared stores and those stores could also communicate with each other too there's also an example if you go to the uh the github repo for x date there's a bunch of examples over here and i made an example for ah it's react list so in this reacts list there's a uh i think it's on code sandbox um i i forget how to get to it actually on code sandbox but um yeah it's a it's a machine that spawns friends and you could add a friend change a friend remove a friend and each friend is also an individual machine too um so yeah this is just an example of you know how you would have many machines communicating with each other so great thank you yeah all right well we have seven minutes left uh any other questions i'll stop talking for now how could i have the type things uh the typings are a work in progress and we're actually doing a lot of work on them rights now so uh two of the biggest initiatives one of them was iraq actually already started and it's using creates model so if you use creates model then um that's going to improve the typing a lot and make the typing experience a lot better so there's even a whole typescript guide over here but the second thing that we're working on is actually um say bs code is actually a vs code extension um which is also going to be using um what's called a uh a type generator and so as you're typing your machines it's going to provide you a lot of really nice hints for like uh just properly typing all of your events and contacts and everything and it's going to be a lot smarter than what you could do with typescript so typescript is one of our hugest focuses right now and we're working on improving the experience the problem is that uh we're trying to express a lot more than typescripts can handle right now so we need something extra like the vs code extension and typescript uh it's just like trying to do graphql and have typescripts behave with it it's hard without an extension graphql sort of does things that go beyond what typescript is capable of and so it's the same thing over here so definitely check out the vs code extension i feel like it's going to help a lot and keep your eye on the upcoming um we have a pr for uh for type gen so this big one over here um lots of good changes coming there and also in version 5 we're going to be cleaning up the types a lot so uh right now the typings are workable um you might run into some edge cases where you need to use any but for the most part um as long as you follow the typescript guides it's pretty solid cool nice thank you [Music] all right uh any other questions that's why i think we're coming up on time yeah [Music] that right [Laughter] it's like perfect you fit it in perfectly [Laughter] this is awesome so like um you know i guess if there's no additional questions uh just talking a little bit about like x state and and kind of like what should we be expecting coming out of x date or is it too early for me to ask no no yeah so um yeah that's a really good question um we did recently or semi recently released this public visualizer which we're going to just keep working on this is also completely open source so this month is hacktoberfest if you want to contribute to that by the time this video airs maybe it won't be october fest but please still contribute um you know pr's if you want to see this improved in any way um but we're working on two big initiatives which is a registry where anyone can basically create these machines and share them um and you know just have like a nice collection of these so that if you wanted to make your own media player but you didn't want to write the machine from scratch you could look at other people's machines that they made and say i like that one it has all the features i need and even if it doesn't it's easy for me to add those features and just copy and paste it over to your application the second thing we're working on is a visual editor so uh you know x-state it has an interesting api it's very object-based and so the reason for that is really to get it playing right with the visualization and also trying to make it as concise as possible um but the ideal scenario is to be able to just visually create this and have sort of a living diagram uh where you can drag and drop and maybe add mock-ups and yeah just like have a really advanced visual editor for these diagrams but the artifact of this not just being a static image but rather being a living diagram that it's basically already coded so whatever you draw is what is reflected in your application and uh i just think that that's really powerful because i've been working with diagrams for such a long time where uh the diagrams are outdate or the code is out of dates or you know things are missing and they're never in sync with each other so yeah we're trying to improve the way that you know developers designers and stakeholders work together with all of these tools um so yeah we're doing a closed beta at the end of the month um and just slowly rolling that out so by early next year expect a public data of the um the visual editor and i'm really excited for it is so amazing and it's great that your repo is already set up for people to contribute cause you know i'm all about that i keep bugging ben on our xgs repo i'm like have little more easy issues for people to actually do so yeah thank you so much and you can follow david on twitter by the way at david k piano it's right up to the top uh top left right there david's name so everybody calls him david piano right david yeah i guess yeah and uh you know keep a lookout but hopefully everybody starts using state machines and checks out stately and uh yeah i really appreciated this thank you yeah and thank you for having me
Info
Channel: This Dot Media
Views: 539
Rating: undefined out of 5
Keywords: xstate tutorial, state machines, xstate js, state management
Id: BJfeWEPBZXQ
Channel Id: undefined
Length: 86min 30sec (5190 seconds)
Published: Wed Nov 17 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.