Managing React Application State Management - Talk by Kent C. Dodds

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is up react-a-thon my name is ken c dodds and i'm so excited to be talking with you virtually in this remote conference and i want to talk with you about managing state management specifically for react so my main assertion here is that react is a state management library and i am going to kind of try and prove that thesis to you through the course of our our conversation here but first i wanted to just show you a couple of things about me i'm not going to belabor this at all you can find these slides right here on my github managing state management slides the one thing that i do want to call out specifically though is epic react which you can find at epicreact.dev this is everything that i know about react put into one place made really accessible for all of you so please do take a look at epic reacts it is an enormous amount of material um and just great learning i've poured a silly amount of time into this and people seem to really really like it so if you haven't heard of it yet go definitely take a look so let's start out with a couple expectations first of all this talk is all about how state management application state management doesn't have to be as difficult as we sometimes make it and that's normally driven by the way that we're thinking about state management so that can make a major impact on the maintenance of your application and yeah again my assertion that react may be all that you need for your ui state this talk is not dogmatic though i realize that my problems are not your problems but hopefully there's enough of an overlap there where we can come to an agreement on uh different ways to simplify the performance and maintenance of our react applications and then here's some just questions that people always ask me and one thing i want to point out night owl that's the shirt i'm wearing right now so i've got a shirt for my theme for vs code it's pretty legit thank you sarah okay so let's talk about state management really it is a hard problem let's think about state just in general what is state so state is basically data that changes over time so it's information information's data it changes over time and anytime you add time any time you add time to anything that just complicates the the whole problem so if if all we had to do was um have some like consistent data it just never changed and just show that to the user that would make everything easy we wouldn't need react we just need a some sort of server template thing and and then you render it and stick it on a cdn or something but no that our our applications are interactive and they change and and we've got you know things on the server that change we need to make our applications react to those changes all of that is what makes state management kind of a difficult problem but because it's such a difficult problem i think that sometimes we over engineer it assuming that maybe something could come up that would necessitate a really flexible solution and that ends up over engineering our solution in general which leads to code bases that are harder to maintain than they should be so let's talk about a couple of the different ways that we can simplify our state management the first thing is and i think this is the most important this is the part that like unlocks everything for us uh is the way that we think about state so there are actually two categories of state that i like to think of there are many categories but pretty much all of these can kind of fit into two buckets either your server cache or your ui state so these two things aren't the same thing and treating them the same is actually my big state management mistake which you can read at in the epic react dev articles there so server cache is state it is data that changes over time but it's actually stored persisted on the server and then we cache it in the client for quick access and the reason that we do this is for performance reasons so if i were netflix for example and every single time i navigate to your movies page or whatever and like every time every user went to the you know information about a particular um seasonal episode episodic um you know tv show like stranger things or something if i hit the database every single time especially on a big release that would probably tear the data database down it wouldn't be really great and so we add a layer of caching between us and the backend so that we don't tear down the database and we do the same thing for client-side stuff as well so for like my own user data or whatever just caching is basically an optimization to avoid uh performance problems and so we have this server cache on the client side so that we don't have to make a request to the back end every single time we want to get some information and that may not just be because we don't want to hit the back end all the time it could just be that we don't want to have the user having to wait on every single page transition to go get some data that they already have in their browser and so we have that server cache where the this state is actually stored on the back end and then we have our ui state and this is state that's stored on the front end meaning that if you refresh the page that state is totally gone and there's lots of stuff like this like the is open state or if you're using enums like you should then a status state for the modal whether it's open or closed um and like the the checkout flow state maybe you store some of that stuff on the back end but some of it you may not really care if the user hits refresh or navigates away or something you don't really need to store all that so that's the difference is like where do you put this state if if it gets saved on the server then that's what what you've got is not ui state what you have is a server cache if it's stuff that's only maintained in the front end it's just client stuff then that's ui state and those two things need to be treated separately so when i'm talking about state and how react is all you really need for ui state that's what i'm talking about is just the stuff that is managed on the front end now of course you can use react for that server side stuff and that's exactly what react query does and this is what i recommend is you actually use react query for managing your server cache because it gives you all the right knobs to turn and whatever to control how your server cache works and you have all those performance benefits of the cache it does a really really good job of this and then once you put all of your server cache stuff in a special place for the server cache then all that's left is just so simple that there's no real reason to bring in other libraries with a couple exceptions that we'll talk about one other thing that i want to mention here is to just keep it a close eye on remix run if you haven't heard of it already go take a look it's from ryan florence and michael jackson creators of react router it is going to change the game in regard to server cache and ui state it's very very cool stuff that they're doing over there so keep an eye out for that but for right now react query is just amazing i'm a big fan and i should mention also that remix run doesn't necessarily mean that react query is totally irrelevant you can use them together but there are some really interesting things coming um i'm really excited about remix run okay so separate your server cache your ui state and now let's talk about the ui state and what we can do to simplify that even further so let's talk about how we think about our state let's imagine that we're building like a twitter or something like that and let's see what our component tree could look like so we've got our app we have a left nav with a bunch of links and a drop down and a button we've got our main content that has our all of our tweets and everything and then our right controls for search and and trends and all that stuff so a couple of questions here what is global state in the context of this type of a structure here well i think that uh you know there there's a couple elements of state um there's the drop down and that would have a maybe a state machine behind it that has the status uh or the the current state of the drop down whether it's open and closed and different things like that um i i wouldn't really put that into global state but i'm back in the day with that when i was all in on redux and and everything i'd just because that existed i just wanted to make it global i just like we we had a place for state and that's just where we stick all of our state and that was a big mistake and it's not just redux that that enabled this is really any like you could do this with context anything that enables that sort of attitude towards state just driving everything to global can lead to some serious performance or application maintenance problems and actually potentially performance problems as well and so yeah the drop down that that state probably doesn't need to live it at the app level okay that is ui state but it probably doesn't need to live at the app level um but what about like the the user maybe the the current user we're going to need the user for the timeline we might even need the user inside of this drop down to know which options to show uh when we click on the tweet button we may need the user so that we have the the profile and the modal up properly whatever there's plenty of reasons that the user would need to be used by all of these components so that's definitely something that would need to be global state and we'll talk a little bit more about like well okay so what about the tweets should that be like that's server cache stuff but like where do we even um treat that um some of that stuff as well so we'll we'll talk a little bit more about that um in the future too um so yeah and then let's talk about the we'll talk about the prop drilling problem as well because like if we just put everything global then we just had to drill down forever uh so we'll talk about that too um and then another thing to think about with like where you put state and like how you think about state in your application is how well does that scale over time so one thing that i found is that the more stuff you put in the global um like name space or the global area of your application the more complex that area area of your application gets and when it's the global thing that touches everything in your application and so you don't want that to be complex you want it to be as simple as possible and so we'll we'll talk a little bit more about that as well so let's let's kind of get into some of these things so react is a state management library it's the one you don't have to yarn out npm install bower install unpackage script tag link or any of that stuff you already have it and for the uninitiated this is how you manage state with react you have react.ustate you provide an initial value for that state that gives you back an array from which we can destructure the count and the set count so the state and a mechanism for updating that state and then we can render whatever ui we want to based on that state anytime there's an update react will trigger a re-render meaning it will call this function again and it will always give us back the most recent version of this count state that's and that's it like that's all that you really need to know i mean we've got lazy initialization and we've got you know certain things like that but like that conceptually that's all that you really need to know about react state management and i think that is conceptually quite simple and if we can push more of our state into that frame of uh or that sort of abstraction will be better off so uh let's talk about like the common question that people uh jump in here it's like well okay so ken that counter sure is nice and i like the counter because i i like that it um it lets us focus on the api and and not uh get distracted by the extra stuff um but uh yeah the next question is like well yeah a counter is a counter but um what about more complex things like if i want to share state across components so this is like tail as old as time we've been doing this since the beginning with react and to solve this problem we just lift state up so if we wanted to suddenly have this count display display the the count from the counter then the solution is to move this state to the least common parent and then pass those values down so our account display can now take the or here we'll take our counter first we'll just do like a refactor right here first so we'll say our count and let's have a on increment click this will be increment okay and then we'll accept those as props so count and on increment click and we'll put those right there and now with as far as the user is concerned that was basically a refactor there are some semantic differences with moving things around like this because now when the state updates the whole app is going to re-render but the user doesn't know anything about that that's an implementation detail for them that was what we've done is essentially a refactor from their perspective so now we want to add this new feature so we've got this countdisplay thing we want to display that actual account and so now because our state is being stored in the least common parent we can just simply pass that down and we accept that and we're done okay it's pretty simple we we lift it up this is like super duper common uh and it's not really specific to react either like this is the sort of thing that you would do with functions so you've got a function it has some state in it then you have this other function you want to like you've got this parent function you're calling into that one but now you need access to that in this other function that that parent calls so you just move that value up to the parent function you pass it down to either so it's a pretty natural normal javascripty thing that we do but sometimes our designs change in the opposite way so like maybe some the product manager comes around and says hey that countdisplay we don't need that anymore and like now it's just gonna say cool count yo and so that's that's the thing and so you might just update it to be that and you're like great i'm done it works and it technically does but uh you know probably a good idea to get rid of the props here or at least that prop um and then um and then oh yeah we're passing that prop so let's get rid of that and this is about as far as we typically go i don't uh it's not very natural for us to to keep going from here because everything's working and especially when you've got lots of components in here that may or may not be using the state it's kind of like a css thing where you don't want you want to touch as little as possible because you're worried you're going to break something and so you just do as much as or as little as you possibly can to get things working and then you move on to the next ticket what i would challenge you to do is to co-locate the state so once you've made this refactor i want you to take a look at the state the mechanism for updating that state and see if it's being used by more than one component in our case it's not it's only being used by a single component so there's no reason for this app to maintain that state anymore we can actually move this right back to where we had it in the first place we no longer need to accept those props and now we can just pass this and we can get rid of those props and this is like a very simple thing we just basically undid everything that we did but it can have a drastic impact on your code base over time because if you think about this eventually everything will end up in your app component like your app will just be managing all the state and this is what happens pretty often we just end up putting things in context we'll talk about that in a little bit and we just put it all at the global and that just makes the global more complicated and you don't want that to be complicated you want that to be simple and so forcing things down the react component tree will have maintenance impacts like a positive maintenance impact as well as a performance impact a positive one so um yeah lift state up and then co-locate state uh reacts this is just this is a thing that we've been doing with react since the very dawn of react uh years and years ago we just keep doing that so let's talk about the prop drilling problem as we lift state up we've got to pass state down to the components that need it just in this simple example we had to lift it up but then we had to pass as props to the counter encounter display but things can get pretty messy if you have multiple like many layers of components and maybe you're passing things through components that don't even care about the state it just happens that their children have to need to use that state or whatever this can be kind of annoying but the reason that i put this in quotes is a problem is because it's actually not necessarily a problem i actually see it as kind of a kind of a benefit to react because uh with other frameworks that i've used things just were magically in the global namespace and and so you never knew who was using what and what um like why what changed or whatever uh with prop drilling you can really easily follow the like and statically follow the code path unless you're doing something like you know props and you know more props and whatever then then things get a little bit uh confusing so i don't typically recommend doing that except for you know components that are wrapping a button or something like that but in general prop drilling is not really a problem but it can be an annoyance and there are things that we can do before we jump to libraries or even contacts which we'll talk about in a second which make it so we don't really need to do those things so first your first line of defense against a prompter link problem is the use of composition so uh here's an example of the prop drilling problem we've got our header we've got our left nav and you know your main content and everything and if there's some state that needs to be shared between those and so you know and based on the children of these different components and so we're going to pass that state we'll pass the mechanism for updating the state and then those will prop drill it further and this is a pretty natural way to write our components because we see things as kind of a black box and we're like okay so this box is in charge of this thing and then this there's a smaller box inside of that box and whatever but often these types of components are actually layout components they're not really managing state themselves they're not really doing a whole lot and even if they are like they're really just responsible for laying some things out not really responsible for managing state and so what if we just kind of change the way we think about these components and really literally make them responsible for laying things out and that's what composition is this is very similar to what you might know from like vue or even angularjs we call this transclusion except you could only translate one thing now you can do like multiple uh but yeah so you've got slots react has had this forever you basically make a prop that is the react element that you want to render in a specific place so the header is responsible for rendering the the logo but it's not it doesn't have to be responsible for creating the element that goes into the logo position it's just responsible for putting the logo in that spot and so if we pass at a prop that says here's the logo i'll create the react element and give it to you then because we're responsible for creating the react element we can pass the state directly to that element that we create we don't have to worry about prop drilling so here is our logo we're going to pass down that state and then our settings needs to be able to update that state and so i'll pass that down whatever the case may be whatever that state may be but composing things slightly differently can make it so you don't have to prop drill nearly as much and michael jackson actually has a great video about this type of composition with better examples if you want to go take a look at that and the react docs has had this for a very long time so you can go take a look at the react docs as well so if composition isn't quite doing it for you or like maybe we're talking about user authentication and literally everything just needs the user object then that's a great situation for context most often context is useful for libraries but yeah there are definitely situations i think probably every application is going to need to use context directly in some form so yeah this is what context is we have our counter and counter display and let's say that we don't want to prop drill like this is prop drilling one layer is that even drilling it's not but just for the sake of simplicity we're going to just say hey i don't want to drill in count and increment i just want to make those available to everybody who renders under me so the way that this works is you make a account provider and we're going to or sorry this is going to be account context and here we're going to say react create context and then right here we'll say count context provider will provide a value and our value is going to be an object with the count and increment and then we'll close that up with account context provider and we'll move this stuff in here and now we don't need to worry about passing the count because it's this component is going to get that from elsewhere and same with the count and increment for the counter itself so we're no longer drilling anymore we we don't need to pass those props we can get those from elsewhere and we can get this from elsewhere and now to be able to get this we need to say hey react earlier up higher in the tree i told you to put a value into a little box for me i need to grab the value from the box because you get that for me and react says yeah sure totally and the way that we ask for that little box that little value is by saying react use context and we pass the context object that we used or that we got from react create context so that's how react associates our use context call with the provider value that we've been provided so here now i'm going to get that value which i'm going to simply destructure into the count and increment okay so we're getting exactly this exact same object here so then i can change on increment click to just simply increment and then here we've got our count and then we can do the same thing for our account display right here and now we've avoided prop drilling for this one particular element of state so we don't have to do that for all the state in our application we'll talk about that next but we are able to avoid this prop drilling just using the tools that react gives us directly out of the react toolbox and i think that is uh really valuable so um oh and it works with the use reducer so if that's your jam that's great um i do have a blog post about how to use react contacts effectively this is not it um it goes into a little bit more depth so feel free to take a look at that blog post so let's talk a little bit more about colocation so you know how i talked about we lift state up and then we want to co-locate it down so this also applies to context and providers and in a typical application you're going to have maybe several providers you'll have a user notifications uh theme and authentic authentication here we have a router so um you know the interesting thing about all of these providers in this pyramid of doom that people seem to always be really concerned about which by the way i'm not i like this is not confusing to me at all but some people are really like concerned about this interesting thing about this is as soon as you make a context people seem to just be drawn to put it at the root of their application and i don't blame them because it it makes it really straightforward you can once it's in the global then you can just move stuff all over the place you don't have to worry about where it is or anything for any consumers but you're kind of hurting yourself and doing that typically what will happen is your file structure will follow the structure of your react component tree and if you put everything at the global then your react component tree or your file structure might look something like this now this isn't a recommendation on how to structure files or anything please don't take that this is just what a a natural file structure might look like for something like this so here we have our source we have providers because these are all global so we're just going to put it in this provider's thing then we've got all of our screens and everything the problem with this sort of thing is that if i wanted to make a change to notifications and let's just act under the assumption that notifications provider is only needed in the notifications components all right or maybe the the theme providers only needed in the settings page or whatever the case may be so if that let's just go with the notifications if that's the case then by putting the notifications provider at the global rather than directly in here means that anytime i need to make changes to the notifications i also have to deal with the global context of the notifications which means i'm working in in multiple directories i'm making changes to different files that may impact other files and and just adds to the level of complexity just because i decided to make the notifications global in addition to that i actually potentially could have a performance problem depending on the way that i structure things because whenever the notifications re-renders i may end up re-rendering more of the application than i really intended and on top of that another performance consideration is the fact that anything that is in your global right here at the top of your app that needs to be on the client before your app can be rendered so that means that you have to load all that code you have to execute all that code and you have to render this before anybody gets a chance to to see anything at all and so this is unfortunate because it means you can't code split any of that logic or any of the you know the um like yeah you just can't code split it and this is not a great thing if uh if it's not absolutely necessary to be global and so we can do instead is sure you can have your app and there may be some things that need to be global but maybe there are some things that don't need to be global like the notifications or the user for the user screen so you just co-locate those to where they need to be and then those things can be code split and it just naturally falls out that the provider would also be code split as well as all of the logic and whatever libraries you're using inside of there can also be code split and then the the natural directory structure that falls out of that is you don't need to have that in the providers you just put that directly along with the notifications and then if i'm working on notifications i'm just in this little area and i don't bother anybody else or any other code that i'm maybe not as familiar with i can just stick in there so it can make things a lot simpler now again this is not a recommendation of file structure you can go read what dan has to say about file structure there but yeah a couple of the benefits here code splitting just works the file structure scales really well and you have reduced interaction you don't have to think about as much when when you just co-locate this stuff as much as you can now i know that some of you are like oh i can't but what about performance and so i just won't need to address that yes sometimes there are certain things that react it just isn't going to do for you and this is like for um you know intense graphics or you got a chart or something like that yeah sometimes you're going to be trying to do things that just aren't going to work with the way that reacts reconciliation works and so for those situations you need to step outside of react a little bit and um after you've followed my aforementioned advice because you may be having performance problems just because of the way that you're structuring things and and thinking about state so after you've done all those things if you still have performance issues that you've measured and you know what those performance issues are then take a look at joe tie or recoil they're very similar tools but i like joe taimore really interesting ideas of kind of stepping outside now i'll mention i've never used joe tie in production i've never used recoil in production but i've researched them enough to have confidence that they can help specific performance problems so learn what problems they're intended to solve and then and then use them to solve your problems if you're having those same problems so let's just wrap up interview it's really important to remember server cache is not the same as ui state if you use react query then you can put all your server cache over here and then and then your react state what's left is actually quite simple and react query makes your server cache pretty simple too so you end up with um you know this really complicated problem has been simplified uh significantly and again look forward to remix i think it's just the bomb state or react is a state management library uh it has all of the tools that you really need for like 90 of the cases and you're probably that you have a 90 likelihood that you are part of that ninety percent so keep that in mind um lift state up or down for co-location use composition when prop drilling is a pain and sometimes you can use context and if performance is an issue look into joe tai that's all that i have for you thank you so much definitely check out epicreact.dev and i'll see you around the internet bye
Info
Channel: freeCodeCamp Talks
Views: 60,008
Rating: undefined out of 5
Keywords:
Id: zpUMRsAO6-Y
Channel Id: undefined
Length: 30min 14sec (1814 seconds)
Published: Wed Jan 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.