High Performance State Management with React Hooks and MobX - KW Intersections, February 11th, 2020

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

In this session, we build a Netflix clone from scratch using TDD, React Hooks while profiling and optimizing along the way. We then demonstrate how easy it is to add MobX into the mix for that extra horsepower (and less code!).

Recorded live at KW Intersections, Communitech DataHub, February 11th, 2020 in Waterloo, Canada.

Complete code here: https://github.com/anzorb/mobx-talk

👍︎︎ 1 👤︎︎ u/dd0_0bb 📅︎︎ Feb 27 2020 🗫︎ replies
Captions
high performance measurements in reacts with multics and answer a front-end architects at Madison's so thanks so much for the introduction Mary it's it's great to be here like you said I'm Software Architect at map 10 and today's we're gonna be talking about mob X a little bit but I don't want to make that the focus of this talk we're not gonna go with that in depth in it we're kind of gonna get started with you know kind of evolution of react in the front end using react hooks and why I think it was actually a great leap for react and we're gonna build an application almost from scratch I I was pretty ambitious at first and I was like I'm just gonna go in and start downloading yarn packages and all this stuff and I realized that that's you know really gonna anger the demo gods so I have the project ready with all its dependencies and and a couple styles but everything else is pretty much from scratch just before we get started how many of your front-end developers or like do front-end cool and how many use react okay and how many use mob x1 good good I that that's great and how many use redux cool awesome mm-hmm so I I try to time this to fit in my in my time slot I like to keep kind of an open forum and you guys can ask questions there's going to be but there's going to be dirty code and for two reasons one is this is a talk so we don't need to optimize everything and also there's it's kind of intentional because later on when we start to refactor it we're gonna it's gonna make it easier to kind of follow along and yeah um I guess we can get started well I'll show you what the app looks like but we're gonna build and then so we get an idea of what it looks like and then we'll dive in so the app is kind of a basic Netflix clone you could say it uses an API to download movies in this case these are action movies you can kind of keep keep keep fetching more and more movies and then you can add things to the queue down here and then you can like which adds these stars at the bottom or dislike so kind of basic but enough to demonstrate what I'm trying to do what we're gonna start with oh one more question I forgot to ask how many of the react developers are using react hooks versus class-based components okay cool so this will be you know for the rest of it'll kind of be an introduction I wanted to start with a class-based component and then refactor into hooks and then into mob X but that would take two hours so we'll we'll kind of go along first thing I want to go over is why I think react hooks are kind of a great leap for react as a UI library right most for most people say one of the biggest strengths of the react hooks is that less boilerplate you don't have to use classes anymore you can create a functional component which can maintain state and that's that's that that is true that's a good strength there's much less boilerplate and it feels more functional but there's actually another advantage that I like and it encourages you to split your state out of the component so it's easier to test and I'm gonna show you this so why that's important is I really try to use test-driven development or promote it as much as I can who's familiar with test-driven development almost a lot of people great for those who don't know test-driven development is you write the test first and it fails and then you write the code to satisfy that test and then you kind of go back and forth you write the test you write the you write more code we write the test you write more code and in the end based on my personal experience the quality of the code was much better than first writing the code and then testing it because that typically leads to refactoring because you know something about how you write tests they're very human readable especially when you have the format as described and it etc etc so traditionally with class-based components TDD is kind of tedious because you write a test and then you have to create this component that man just state internally that has a bunch of Dom elements to satisfy your test case so most people when they do that they write the test and then they go and actually create you know some Dom elements just enough and and then they test whether the snapshot matches or not which is totally fine but if you have a component with a complex state with lots of permutations you're you're you're left with a lot of snapshots and it just it feels much cleaner for me personally to test the state part of it separately and to leave the elements and the components as dumb as possible so that you can test every permutation just like you do with a node.js program for example you have some sort of input and you test the output and you can test the output in one line you don't need snapshots you don't need anything like that and then once you are confident that you've tested your state you bring it in as a hook into a higher-level component and then you test individual pieces that are involved using snapshots by just giving them some props now you don't have to test you know what every component is going to be like in the tree based on five or ten or a hundred different permutations of your state so to me that's actually the biggest advantage is that you know you can test States separately so let's get started I have yeah this is the other stuff that I kind of mocked up before is i mocked up the response that I get from the API server this is library called just mark fought the mock fetch that marks fetch requests and for now I'm mocking you know one page of movies and a second page of movies because that's something I wanted to show so I've also marked out what this what this component should do on a state level and obviously if we look at it here it should be able to fetch movies and populate the top area we have a little fetch button you should be able to add things to the cue and you should be able to like and dislike things so we know ahead of time you know what what are the what's the functionality so we can go ahead and get started so for those new two hooks or those who have used hooks there's a library called testing library react hooks that lets you test them in isolation without having to have them inside of components I found it very useful it has a couple caveats that we go we'll kind of you know see as we go but for the most part it works great alright let's get started so the first first test is actually you know rendering or let's make sure that the hook returns the API that we expect that's usually what I do so to this result object and we'll call the hook use movies okay the result object has a current property this is something from render hook and that's gonna return the current state so what first thing we'll do is just just to make sure it works we'll save the result but current movies to equal an empty array okay let me make sure this is running a bit bigger okay yep so the test failed because there is no file called movies right it's usually how tidy D starts so we'll create a file called movies J s in there we'll export a function called use movies and if I'm ever stuck please help this is how these live coding things go you know you can never expect what's coming and that slide you saw was one of two slides I prepared so you know okay so as you see the test passed actually I'm gonna comment out the other test just not to have these false positives but myself on the back too soon too early so we have a hook and that exposes an empty movies object fine so now we're also going to have a cue because that's gonna represent the data at the bottom we'll come back and fix the test and we're gonna have like dislike and add to queue functions so we're gonna do this is gonna be like just like add to queue and then we're gonna take this and we're gonna do check off maybe there's a better way to do this but that's what we're getting for now and then we're gonna start without cue like and there's one more actually we'll call it fetch all and this is the one that's gonna fetch the list see so that's that this file mm-hmm okay fetch all to be a function the test fast okay so we we already know kind of what the API is gonna look like of this hook great now let's actually fetch some data so we're gonna render the hook again and we have to perform an asynchronous action obviously because we have to make a server called using fetch so there's gonna be some async await in the picture just to make it you know nice nice and clean but there's one thing that you have to do any time you perform an action on a hook like call a function that changes its internal state you have to wrap it in an act and react provides an act function from their side for testing which is wrapped in this testing library but essentially what it does is it ensures that that all the state is resolved by the time I guess committed by the time you actually have to expect a value so rule of thumb anytime you call methods or anything like that wrap them in an act so it will be something like this and then result current fetch all now this is an asynchronous function so we'll await that and then we have to pass a sync and then because the contents of act are asynchronous we also have to await act otherwise it's not going to resolve in time and then we're gonna expect that result that current that movies is going to be our mark movies so the request comes back in this form there's obviously more data but the whatever parts we need to care about are in here because they have an IMDB ID and a search so since we only care about that we're gonna just do search okay mark movies actually we don't need to do that because that's that's it now the test fails and it says it fails because you're it's expecting to get all these movies but it got an empty are a cool let's let's make it get all those movies so what we're gonna do is we're gonna create an async function called fetch all okay and then we're gonna await the type for a live demo we're gonna hit this URL I'm gonna put it in these ahead of time just to make life easier and this is gonna give us a response then we're gonna say new movies equals a wait rest JSON to get the JSON data there's not gonna be error handling that's not that's out of scope for this and then we actually need to populate movies somehow and this is starting to become stateful right so in react hooks what you need to do is the equivalent of a state is you have a disused state hook which exposes the name I guess or the variable that holds the actual state followed by the setter function to the state so in this case you're gonna go movies set movies and we're gonna say use state @mt array and we're gonna import use state via SCOTUS trying to be too smart from react okay and we're gonna make sure before I forget because I'm going to that we're actually passing movies right through and in here what we're gonna do is we're gonna set movies to the new movies we get dot search because we need we just need that part we don't need anything else and then we make sure that fetch all is also exposed okay so the test passed which means that we're now making a successful request to the API and getting data back cool let's move on to the next thing so as I mentioned before where we want it to be able to go through multiple pages and the API returns I think ten items at a time so let's do that we're gonna copy the same things with it last time but we're gonna call fetch all twice and then when that comes back we expect the result to be I guess we'll have the new page first and then the old page right because you want to see the new stuff first so we have this mock movies page two we're gonna have that search and then movie like movies yeah so this should have both of them let's see our test our test fails and our test fails because it's that it doesn't have page two in it right so let's make that work so we have page that we pass into the API endpoint what we need to do is actually pass a variable and this is another concept of react hooks is any time in class-based components you'd have to store an instance variable on this in react hooks you use a use ref at least that's my rule of thumb we'll see you later on when it comes to functions but so far hasn't failed me so that's that's that's the way I do it so we're gonna store page as a variable we're gonna start with one because I don't think it starts with zero for that particular endpoint and any time you want to so use ref is the reason you want to use it for instance variables is because it maintains its current value throughout the life cycle of this component so from the time it's mounted to the time it's unmounted so anytime it re-renders the value holds the same so that's why you would use use ref in this case so and if you want to access the value you we do page that current so that's the current value of you know that instance variable so let's take a look the tests still fail right because we haven't incremented it so we need to do page current plus plus okay now it's right now it's going to suck it's showing stuff from the second page but not the first right because we haven't actually appended you know the movies together so what we need to do is we're gonna take what's currently inside of the movies state object and you know this was this wasn't very well documented just like set state isn't really that documented that you can paddle it that the first parameter is the current state but when I found out it made things so much easier and I'll kind of go into that a little bit later so what we need to do is we're gonna return a new state actually I don't even think you need that if that has new movies that search followed by the movies that are there right now okay test pass so now no matter how many times we do fetch it should fetch the next page I don't have any mark data for page three so we're not gonna worry about that we're in a trust that it works okay adding movies into the queue so when I was kind of thinking about the architecture of this one way to solve this problem is half q as its own state but and then just you know when you have a movie you add to the queue just push it onto the queue and the problem with that is things can get out of sync so for example if you have some movies in your q and Netflix and Netflix doesn't have the movie anymore you have stale data in your queue right so typically you either like you can write code to keep them in sync but in my opinion the queue should be representative should be like a snapshot of what's in your movies but that that's been flagged as the cue so let's let's kind of see how we can implement that so first we've we have to fetch the movies then we're gonna call I'm just gonna use this function oh we're gonna need to this so I think this is the first time we're calling something that's not asynchronous and we're gonna do add to queue and we're gonna pass it one of the movies that's currently in the state object right so we don't have to mess with you know some data being out of sync or anything like that so you can do result that current movies and let's say the fourth one and then we're gonna make sure that our queue has one movie in it which is the the movie weekend we push them right so we save it the test fails because it's expecting us to have this IMDB 4 movie let's satisfy the test so we're gonna do function add to queue movie for those who haven't used react we're gonna write a lot of code to do such simple things but it is what it is so what we need to do because the philosophy of react without without using any frameworks and kind of redux as well is you never mutate state directly you always return new state and which means that I can just modify movie I have to create a copy of the movies array create a copy of movie and splice replace the item you know in the array with a certain flag so in this case the flag is gonna be in queue so let's let's do that so we're gonna take movies so I'm gonna say movies copy equals movies and then we're gonna find the index movies index our movie and we're gonna splice in place Wow sometimes this is why I don't worry about AI just yet because if they haven't figured out how to do that I'm being totally I'm totally kidding so it'll be kidding okay so we're gonna splice this at index which is where that movie is currently we want one item and we want to replace it with what's the copy of the movie and we'll just add in Q as a variable and say true and then we're gonna return the copy of the array and this is how this is how you update arrays in in state in react you would do the same thing you know outside two there there's tools to help like there's an update function in in react tools but you know we're getting we're going low level so okay so we're gonna expose add to queue so the test still fails and the test fails because it's looking for Q to have that item and it doesn't all we did was set movies has not so what we need to do is kind of make like a you know like I'd make you a snapshot right or maybe there's a better words for it so we're gonna filter movies on this and we're gonna return movies that are in Q cool okay so far so good next we'll do liking a movie so we can basically copy a lot of this and we're gonna change this to like the API for like is would be the same just pass in the movie and then instead of the Q we're gonna say what's the best way oh let's map that actually so we're gonna go through all the movies and we're gonna map through them and retrieve their let's call it score in here and then in the result since we have how many one two three four five we're due for five and then the fourth one my counting zero one two three four well okay the last one should have a score of one because that's that's the like I think let's find out now I'm going to edit the data slightly just to add some scores just to save some boilerplate yep so the test fails because it's getting a zero but we're expecting a one good because we haven't built the phone we haven't put together the function yet so I'm gonna copy this cuz it's gonna be very very similar because we're again just editing one item and we're gonna like this movie instead of in queue we're gonna take the score of it and say movie that score plus one I think that should do it and then we expose like fast and we can do the same for dislike now you know an optimization obviously the two functions are so similar but just for the sake of the demo we'll keep it the way it is now and then obviously you probably don't want things to go below one but you got purposes of the demo and we're gonna call this dislike the test fails because it's getting a zero we're just gonna copy this function paste it in and subtract one and did it work because we didn't expose it okay so that's it the test part is done now we have this react hook that we can insert into basically any component and wired up to actual Dom elements we're confident that it works we're not using snapshots so we're not digging through Dom elements just to figure out what state it's in you know so let's go ahead and wire it up so we're gonna take app make sure it's actually running somewhere Oh any questions so far I go pretty fast sorry I didn't know how much I didn't know how long was gonna take so I'm like the movie state inside which flag like mm-hmm mm-hmm yes so the index was there basically if you want to update a single item in an array and react is you copy the array and then you find where that item is and then you replace it with splice with a copy of the item plus whatever attributes you need and that's from what I've seen that's generally the pattern there's easier ways though but that's generally the pattern anymore all right so let's wire it up let's get to the fun part okay so we're gonna import use movies from movies so I'm going to just create a bunch of components so we look at the one that works now we're gonna have a movies component we're gonna have a cue component within the movies component and the cue they're gonna have a movie component that they reference and then we'll have a rating component to actually do the stars that's kind of the structure I'm thinking so movies don't mixing and matching different styles okay so we're gonna return just a div we're gonna pass in a movies array and then we're gonna map through the movies and then return a movie component which could use better wording but takes in a movie we'll use the key of I am IMDB ID okay there's a bracket missing perfect so now let's build the actual movie component which again could be a better word but you know it returns div the I looked at the API and and we have a few fields I'm gonna just put them in but obviously you know if using typescript or something that you can actually infer the interface early on and the test and all that but that takes a lot longer to demonstrate so what we'll do is we'll do movie dot title and then movie dot poster is gonna be an image okay that should be good I like I said earlier I added a few classes so so this one would call movies and the other one that's very similar but the reason I want to keep it separate is when we start profiling it's just easier to see the two different components so you know just bear with me there movies and we're gonna pass in the movies right here and then Q takes movies as well now we're gonna actually use the hook so we're gonna say fetch all cuz we're gonna have a button that does it and then we're gonna have a movies array use movies so this is how you use a hook that we just built I'm gonna add a button and I'm gonna say fetch it's gonna call fetch all okay stop it okay stuff is rendering my classes aren't set up because they're not in here okay let me get some CSS classes okay much better but obviously the queue shouldn't have the movies in it so we're gonna go into app and make sure we're passing in the queue inside of the cube at the moment it should be empty so that's one part of it now we need to add our add to queue like and dislike buttons so let's do that we're gonna say add to queue the slack and so we'll say add to queue and pass in the movie copy that like and dislike and then we need these three functions passed in oh and we also need them passed into here from the top component so let's see how we can do what that works and then we're going to expose them and should be able to just copy that let's take a look okay we're adding things to queue like and dislike does nothing so let's implement that mm-hmm so we'll have we'll add a ratings component at the bottom that takes in a score and you pass in a score from movie the rating component a ratings component it's a score and it returns a div let's see unicode star let's find some stars that's that a cool looking right okay that's one two three four five and splice that from zero to how many stars there are toss it on a thing and I'm mixing like okay so that should should do it let's see they did not okay no actually did not because the data we get from the server doesn't have scores in it and we're trying to add one to something that doesn't have a score in it let's see what data would get back yeah there's no there's no score because score is something we're keeping track of internally in the application so I'm surprised there wasn't any error which is kind of scary I'm not sure if react hooks are hiding them but you would definitely suspect because if I if I log oh no sirree not now reload movies and we have like it's a third one so yeah we get another number I guess JavaScript's like oh it's not a number don't need to throw an error everything is cool that's why I used I ascribe yeah Wow alright so let's fix that and we need to fix that actually in our API call when we fetch the movies from search we need to map and we're gonna return Oh too many brackets we're gonna return and just set the score 2-0 that should do it I'm missing squiggly no okay let's see hey there we go we got some stars yes sorry which state oh well it's already in there it's inside of movies right now it is so are you saying like offline or persists so that's when you'd add a persistence layer and likely you know when the application starts up you merge it from your persistence layer to what you're getting you know from the server or something along those lines yeah which is a good topic for a talk for sure so anymore it depends on the application if you want a progressive web app then you can use local storage for something like this because it's fairly simple you just hash the IDs and at mapped in we use index DB heavily because we have I don't know if you've seen those kiosks at the malls those are our kiosks so they need to work offline all the time so we store an index DB is very versatile because you can store blobs so we you can store images and other binary type you know data in there but when it comes to selecting a persistence layer neither mob X nor react kind of dictate or even react hooks what you choose you kind of have to find out for yourself okay so cool that this this app actually works but if we want to build something that's gonna perform well we need to optimize it right yes and the queue hey give it gets an air and that's because we haven't passed in the functions to queue right because ideally you wouldn't want those buttons down there anyway so the best way to do that is you can just say okay if active queue is not available or if it is available only then do you render all those buttons and otherwise you don't so now you can't do that but the stars still show up right and this is the advantage of having the data having the queue a snapshot of your movies right is the data isn't sync okay let's move on to optimizations so if you look at if you look at how Netflix is built on some of the other apps they actually had to do so much optimizations because they had to run on PlayStation 4 and a bunch of other low-power devices so one of the key things you want to ensure is nothing should render unless data changed which forced it to render right react out-of-the-box right now will rerender everything so if I hit like it's gonna render the cue mind you it kinda has to because the stars are in there but if I fetch more movies it's gonna rerender everything in the queue in fact if we like one of the movies is gonna be render all of the movies right that's how react works out of box and I'll show you how you can detect how you can take a look at that so react has this really cool profiler I'm gonna see if I can zoom it in a little bit so typically you wanted to perform I like to perform one action so I like to start recording perform one action and stop recording and then it'll show you all that all the rear Enders that happen in the tree so in this case we're gonna see what happens when we like a movie we're gonna start profiling we're gonna like a movie we start and stop profiling this is the last thing you want to see if you're building a high performance application because this means the whole app every single component sub component everything we rendered right so if you click on stuff you can actually see why it rear entered right and you know there was one actually legitimate rerender I think it was this one know which movie did we do the second one so it's this one yeah so this one we rendered because the movie actually changed but then the other ones rerender because add to queue like and dislike changed and we'll get to that in a second but also the queue changed even though the movie is not in the queue and the movie in the queue update re rendered and the ratings component in it re rendered even though none of that changed so the first thing you can do to optimize for all of that is put all of your components inside of react memo right react memo memorizes the component and then does a shallow check on the props and if the props are the same it simply doesn't rerender the component so we're gonna do that first so let's do this let's try this this this and app why not okay my startup with a little bit no that's not what I want to do okay sorry my keyboard is I have the Apple three them saying that their keyboards suck so it's a bit of a struggle sometimes mm oh and then do these by hand okay save it seems like everything was fine okay let's I'm gonna sleeve this tab open and I keep the tabs open as we kind of progress just to so we have a good baseline for comparison and open the profiler gonna fetch the movies I'm gonna add one to the queue because we want to see the hole we want we want as many you want as many components populated and rendered so that you can actually see what we rendered one right and then we're gonna start profiling we'll take a movie that's not in the queue hit like stop profiling okay it's looking better it's looking better because at least some things are not being rear-ended so the ratings for each movie is great and it tells you did not render during this session that's perfect the the qre rendered but the movie in the queue didn't and either it's did it's ratings so already there is some improvement and this is kind of a gotcha that i realized a while back but if you look at why these other movies we rendered is because at the functions that were passing and changed which is which is which was so foreign to me because when you write class-based components you know you pass in references to those functions and if and it's fine right so I was like it's got to be hooks there's got to be something to do with hooks sure enough it was and and what was happening was the way the react hook rear Enders top to bottom every time you set state which means that every time it rear Enders it creates a new instance of add to cue a new instance of like a new instance of dislike so it's a toy it's a totally new reference which is why the component thinks that you're passing in something new and the components we render and the cheapest easiest way to solve this problem is by the rule of thumb I mentioned initially where if you need a local variable whether it's a function or or it's a variable just use raffle so we're gonna what we're gonna do is we're gonna create local versions of the function and then we're going to cash them you could so yeah I find that if all your function does is a call set state on an on something then you don't benefit from use call back because use refuge it just handles it for you exactly because the set state already has the movies object in it so you don't really need to use call back and I found that use ref for me personally it's just it's easier to reason about because this way all local instances are you know whatever I used to use on this in class based components now is use ref right so I just I like be consistency in that regard so we do like just like okay and then make sure that we're passing in like that current dislike that current now a lot of people who haven't used folks are kind of disliking hooks right now and it this is a little bit backwards I I totally agree which goes great into my next part of the talk so okay we don't care about fetch all because we're not passing it as a prop anywhere I think that should do it so I'm gonna leave this open again we're gonna open another instance fetch the movies profiler add something to cue start profiling will like this movie cool okay so now only the movie that changed in the movies cue actually rear Enders and it's ratings because it had a star that changed the top level component which is the app and the movies component we rendered because if you look at it hooks changed so because this used movies hook is at the top level whenever it changes it's going to propagate down right typically react is good at memorizing react is better at memorizing items and lists because they have an ID if they have a they they have keys we can we can go further optimizing but there's I wanted to kind of jump to the next part and that's how we can introduce mob X into this and kind of refactor it and see its benefits before I do that any questions just the functions you mean not really because it's just storing the reference to it and then it gets cleaned up if the component that you know asked for the hook gets unmounted then all of that is out of the memory right so it's only there for the duration of the lifecycle from mount to unmount and then it's gone no you don't have to yeah should be fine why isn't default because let's say mmm that's a good question I I've always wondered that too maybe they kind of left it open so that people can have their own implementations of memo and I'll show you how mob X does it's very similar or maybe they didn't want to imply because by default memo does a shallow compare but you can actually pass in your own function and do a deep comparison if you want right so maybe for them it was easier but I think actually the biggest reason is they added it later on so maybe it was just to keep things more consistent do you know that's a good point because the if we would have mutated the movies array in place then the memo would with wouldn't we render the component because it would you wouldn't know that the movies changed right because the reference would remain the same so thanks Brian yeah that that's that's why so for anyone who just picks up react it it just rear Enders everything and then you kind of optimize as you as you go along yeah okay let's move to the fun part hmm think yeah okay so we're gonna take we're gonna take our react hook and refactor it for mob X so I'm just gonna copy the file and paste it we're not gonna do the tasks first for mob X just you know just to save some time but then I'll come back to the test and refactor them after so because that that's gonna be that's gonna just take a minute okay movies mob X so we're gonna export a factory function will call it movie store and inside we're gonna build a store which is going to be an observable and observable is something you get from the mob X library we're also yeah from marvex and then we're gonna return the store and let's copy some stuff over so we're gonna have movies we're gonna have Q I'm gonna copy paste some of these methods and then we'll refactor them as we go along one thing I should note so one of the biggest differences with mob X is that their philosophy is the opposite they they want you to mutate state in place as much as possible that's actually one of the strengths of mob X is you mutates State in place and it figures out what it should render and what it shouldn't render and performs you know optimizations on that level when we were gonna kind of see that so first example of that is our fetch all function so we're actually going to right now we have we're returning a new copy so what we're gonna actually do is we're gonna take the movies in the store and unshift them to insert new movies in at the start that's a lot of dots okay so we're we're modifying the array in place by inserting those items in there's no more use use ref so we don't need to do page that current in fact you can use because this is a factory it's gonna create B it's gonna give you local scope so if you need any local variables you just store them on top before you return the actual function then we have there is something you have to do anytime you're mutating state is you have to wrap your function in an action in Bob X and what that does it's it's a to kind of enforce some of their debugging tooling so that you know what actions you're taking but also it keeps all of your state mutations in one transaction so that if you have one component that's listening to movies and cue and you're editing both movies and cue in one action it's not going to render twice it's going to wait for the whole action to go through and then as one transaction applied the mutations and render the component once so you can actually use it without actions it it's it's it's it's an opt-in but I I recommend actually you know wrapping things in actions so that should be good for fetch all will take add stick add to queue this is where the fun part starts and we're actually going to take all three just like that and just have to wrap them in an action so it helps with the debugging tools and marvex did kind of like Redux tells you what actions you're committing but also all your state mutations are done in one transaction meaning that it doesn't do any caesarea renders if like two of your things would effect the same component so it batches updates to react inside of transactions okay and one more thing okay perfect now gets get rid of this I don't think we need that anymore we don't need any react stuff anymore so you would because you do want the badges and that we want that performance in production yeah but it does have a benefit in development because it you can you know use developer tools so we're gonna take move this out and go movie in Q equals true I'm gonna say movie score plus plus and movie score minus minus so in place yeah I mean who wants to write more code right one thing so before we had that Q that was kind of a snapshot in mob X anything you said as a getter automatically gets memorized for you and only returns you know I guess reruns when any of the observables that it listens to changed right so I'll show you an example so all you have to do is set get Q which is the standard es5 getter and then you return store that movies dot map now that filter m dot in queue so this way only when movies change does it recompute this function otherwise you're getting the memorized version at all times I think this is ready to get wired up so let's go in here we'll import it store from movies and so mob ex works without react in fact I've used it in backend applications as well the react portion is kind of secondary and that comes in a library called mob ex react and in order to actually have your components observe things in your mob ex store you need this observer function and it works very much like memo in fact it's actually a wrapper around memo with a couple mob x specific things where it observes so with your mob x react and we'll just take all the memos put observer you don't need done anymore and it also comes with a function called use local store and that's actually a way to wrap your factory function of your store within a react hook so that it's available to be used so use local store all we have to do is do this and pass in our movie store imagine it works on the first try okay quick look movie store is not exported from movies didn't let's make thank you I will not leave the inspector okay so it works it's great so that was like that was showing how you can how quickly you can refactor something that you wrote with hooks into mob X shave some code which we all like I'm gonna show you a couple cool things that you get for free when you do it like this so we'll run the profiler we'll do the same exact test we did last time so I'm gonna like this movie I'm gonna stop so the only thing that we rendered is the movie and its ratings everything else remained the same and it did that automatically I'm going to show you one more thing so what did I want to show oh let's say we have let's say we don't care about showing stars in the queue right so because it's shown somewhere else or it could be any other piece of data but we're basically what we're gonna say is and I should have shown this in the non mob X version for a bigger aha moment but you can kind of take my word on it what we're gonna do is in when things are in the queue we're actually gonna get rid of this these stars or actually first I'll show you what happens when we do like something in the queue right so obviously you have the movie in a list that re-rendered and it's ratings and then in the movie in the queue and it's ratings right that's what you expect because those are the things that changed now if we didn't care about the ratings and the queue the non mob X version that been no way to not have the queue movie we render if we had changed the ratings on it because it was a snapshot of it and there's no optimizations done for you in mob X you get that stuff for free and I'll show you what I me so in the queue we have let's just say that if there's no like button there is no rating just to keep it simple okay so now we'll fetch to queue there's no more rating and take a snapshot we're going to like the same movie that's in the queue which means it's it's making a change to that object stop the queue doesn't rerender neither does the movie in it so the way this works is mob X keeps track of everywhere of every observable that you reference in your components and if those observables are no longer referenced it doesn't rerender the component and does that for you it's an update but it's boarding change back right if you didn't want to pass in the movie right right right no you're right but it's possible yeah no no it's it's perfect and then one more thing before we jump back and refactor the test this is just gonna take a couple of minutes another reason why mob ex is why this this this kind of architecture is nice is because you can avoid prevent prob trilling right so we can quickly what we're gonna do is we're going to from our mob X store we're going to export default react create context and just keep it empty okay and then we're gonna import it in here this is kind of the pattern that we follow context okay now what we're gonna do is we're going to create a provider and we set the value to the store do that in a second and then okay we're not gonna pass anything anymore so we'll just do that and now in our components since we use the context provider we can use the use context hook to get access to that version of the store at the time to that instance of it so we can do movies equals use context and what did we call it movie store context and then we don't have to pass it in anymore just make sure it's defined okay we'll add a couple more things in so and then obviously this one also we don't need to pass functions in anymore I mean it's it when you're looping through a movie array instantiating a movie with that with that data it makes sense but functions really I prefer just using context for that so in that case all all we need is this and don't movies anymore I think that should do it let's make sure everything still works oh you didn't and it's because we're using movies instead of cue [Applause] yeah everything still works so that's how you would basically create usually when we when we when we create our componentry each kind of each state would be living next to the parent component and then it'll trickle down to the children as they need it and then when we test the children you can in your unit test you can just basically mock your provider and test that they're actually behaving the way that they should right that they're calling for example you know clicking on that button should trigger like and so you mock up the context provider of your store and you as a just function and then you make sure that when you click the button in your test that that the spy gets called right so just just you know a little bit about how we do that so one I wanted to do one thing and then we can do the questions let's go ahead and make the tests work in mob X just show how how much how easy that is to mob X duct test okay we're going to rerun it here we're gonna import movies store okay we're going to take the line where every line that we rendered the hook and just do Const store equals movie store because it's a function we're going to take everywhere we do result dot current change it to store and we don't need we do need a wait for the fetch all but we don't need to act anymore because we're not anywhere near the react ecosystem so we can take that out I think I have that in multiple places so I'll just take it out everywhere okay and anywhere we call a function can do that okay taught us fast yeah but that was that's basically it and we can do questions yes up sorry so I think it does a lot of magic under the hood right I usually when I compare to react or redux which is immutable Redux does very little under the hood it's a small library but it makes you pay for it at work whereas ma box it's it's a larger library because it kind of tries to guard you against those things so from what I've seen if you follow kind of the general practices of keeping your transactions inside of an action there is it definitely there's a learning curve but from my personal experience because I think it's about picking the right tool for the job personally at mapped in we have all of our consumer facing products use mob X and then our enterprise like our CMS uses redux and the CMS you know you it has undo and redo state and there's like a million actions and and things like that so you get kind of some of that for free out of the box because of immutability whereas all of the other consumer facing applications I always thought Redux is kind of an overkill and worrying about immutability because you're just fetching data from the server making manipulations maybe caching it and then displaying it to the user in the most efficient way possible usually because our kiosks they have to run a very low-power hardware and that's why it's important to make sure that we're not taking CPU and GPU cycles to rerender stuff yeah but in terms of the trend I have seen the trend in fact I've been following I don't know if who know who remembers but there was an actual es6 or es7 observer spec in the works for job for Eckman Eckman 6 which would allow you to observe things for changes in a very similar way and it got kind of tossed away because proxies came around and if you've seen how proxies work is they let you wrap an object and you wrap access to it and then you can basically create a pubsub notification system with that and if you look at the mob acts observable each one is just a proxy so it looks like a real object it looks like a real array but it's wrapped so I feel like you know even though there is a trend with proxies that's opened up more doors to make mutable States more you know I guess safe so I mean synchronous operations are synchronous in JavaScript right so they're gonna happen in order and your tree is going to change your state tree in order if you have a lot of asynchronous operations they're going to modify the state whenever there they're completed right it's up to you you as a developer to ensure that the order in which a synchronous functions come in kind of happens in the in the order that you expect right but I I'm not sure if that's any different in in Redux like I feel like you still have to with either sagas or what's the latest way to do asynchronous it's been a while James like I don't know all right yeah yeah sorry there was one more question no okay thanks guys
Info
Channel: Anzor B
Views: 2,742
Rating: 4.8279572 out of 5
Keywords: mobx, react, react-dom, javascript, frontend, front-end, jest, tdd, netflix, ui, ux, design, programming, 60fps
Id: RougY_BYANg
Channel Id: undefined
Length: 75min 19sec (4519 seconds)
Published: Thu Feb 27 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.