Picking From 20 React State Managers

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
which reacts tape manager is the best which react state manager would i choose i get asked that question a lot hi i'm jack harrington a principal full stack software engineer and in this video i'm hoping to answer that question i've done a lot of research over the past week building 22 separate little applications all of which implement the same thing but with different state management styles including 20 different state managers if you can believe that so with this video you will get all of that code for free and of course also a conceptual framework that i've kind of developed during this exercise of all this research that has helped me understand the different state managers and how they all relate together and what the kind of generic models that they are implementing are and i hope that having gone through that will help you kind of bucket them into categories and help you figure out which one or which category is the right one for you all right let's jump right into working through that mental model so the foundation of our mental model are react hooks the basics use state and user user to create state and then use memo use effect and use callback to monitor that state and that has to be the foundation for you the better that you understand how to use react hooks effectively the better that you're going to be able to make use of these state management solutions as i went through my research there aren't a lot of state managers that are supporting the class-based state system there are a few but absolutely 100 across the board all of them are doing hooks all right so let's go and take a look at our application and then we'll go into our prop drilling example which will be essentially the starting point of all this okay so here's our application it's a stopwatch application i can start and stop that stopwatch and then once that stopwatch value goes across two seconds it actually makes a fetch call that seems a little bit arbitrary i know but this helps demonstrate three important properties of state management so the first one is just getting and setting basic state values and that's demonstrated most by this start button it basically just toggles a boolean the second is asynchronous work here and here how state managers manage asynchronous workflows is very important because we do a lot of asynchronous work in javascript and then the third aspect is around connections between data so in this case that's demonstrated by this stopwatch and when it the count goes over two seconds then it prompts this json fetch over here and that just allows us to explore how the different state managers allow you to connect business logic and look at values and things like that now the reason that i created examples that were this small and simple is because i want you to be able to go and take the code take all of my state out of it put your state into it and see how that model works for you but i did want to have an example that showed those three key aspects setting and getting values asynchronous stuff and then connections between values in the same model so let's go over and see how this is done using the absolutely basic stuff built into react no state manager at all all right here we are in the example code and you can get this over on github we are in the examples directory under hooks prop drilling and then in source under app.tsx every one of these is going to have an app.tsx file it's pretty much largely the same between each of the applications and then probably a store.tsx file that contains whatever the store business logic is so let's take a look at that app.tsx first and if i scroll down here to the bottom we can see we have an app in this case our application state is maintained right at the top of the tree so we've got and use application state custom hook that has coming out of it seconds running names and on toggle that seconds value is what goes into the timer display that's located up at the top with stopwatch and then the seconds and then there's running which goes to the timer toggle that just basically does that flip between starting and stopped and that gets the running value and then that method then gets called to do the toggling and then finally there's names that gets the list of names and this is the same across all of them some are connected some are done different ways this is the prop drilling variant so now let's go into that store.tsx file and take a look at that so right at the top you've got the definition of the application state which is the output of this custom hook it's got some state in there for the seconds and the running as well as for the names that we get back from the json file which is located over in the public directory under names.json it's got a names key that has a list of names and then we get to the really fun part which are the use effects so up at the top here we have our timer use effect so it looks at the running piece of state and when running changes it gets rerun and it looks at that running value over here and when running is true it creates a timer and then it returns a cleanup function that when that state toggles again that cleanup function gets then called and we clear the interval and so it keeps kind of itself nice and clean so let's have a look in some more detail about this timer here because it's actually kind of interesting so we have set seconds and now you normally see with a setter like that you're just going to take seconds and then add 0.1 to it sure right but in this case i'm doing something different i'm giving it a function and that function is getting the current value of seconds and then adding 0.1 to it so why am i doing that as opposed to just doing seconds plus zero one well here's the reason so what happens is when running goes from false to true the first time i hit the start button then the value of seconds at that point is going to be zero and what happens is in this function which is a closure that value of 0 gets captured and so if i just had seconds plus 0.0.1 like that i would get 0.1 0.1 0.1 over and over and over again this is what's called a stale closure and it's a real bug bearer when it comes to these kind of asynchronous effects when it comes to use effect or any kind of use of state use memo or use callback these kind of stale closures can really get you so understanding that is super important and having that really good knowledge of effects is also really important because again all of the state managers are going to look at layer on top of that knowledge now this second one is also kind of interesting the second one is where we look to see that seconds is greater than two and if it is then we go off when we fetch that names.json and we set the data with that and so here's the interesting bit there right instead of just using say seconds like we normally would we're using an expression seconds is greater than 2 which is either going to be false or true and so what this does is it basically turns this use effect into a one-time state changing hook so it says basically okay we're going to go from false to true we're never going to come back and we're only going to do that once and so we're only ever going to go and do that fetch just once so the really nice clean way to make sure that you only ever run this fetch once is just by using a an equation in there an expression as opposed to just looking at seconds and then you'd be running through this use effect every single time that seconds changed so hopefully this has given us a solid foundation of understanding of what the application is and how to do it in the simplest possible way with the tools that we have available to us just based in react let's go back to our conceptual model and talk about something extra that we can add into our basic toolkit of hooks so what i want to add at this level to our conceptual framework of state managers are finite state machines or really in particular x-state so it plays the same role as like a u-state or a user reducer and that it manages some state but it does it in a different way so let's take a look at our stopwatch and the finite states that exist within our stopwatch so we have the stopped state which we start in and then when we hit that toggle button we then go into the started state we hit the toggle button again and we go back to the stopped state and only in the started state can we get the tick messages and then increment that count forward so it's just a nice conceptual way to think about machines or state management patterns that fall into these particular states and some great stuff so let's go and check out how that's actually implemented in the code all right so over in the examples directory we have the fsm xstate directory and then within that we have the store and we're bringing in some x date stuff here we're bringing in use machine which is the hook that allows you to bring the machine into the react context and then we have the generic create machine which allows us to create a state machine so we have our events this case toggle and tick we have our context this is the data of the stopwatch and then we've got the definition of the machine the machine is called stopwatch it has an initial state of stopped and you can see the states listed here in the states key there's the stopped state where you can toggle into the started state and the started state where you can toggle back into the stop state this invoke is run when you enter the state you can add methods to get run when you enter the state or exit the state and then this tick will go and set the seconds plus 0.1 and then it will do the fetch if that threshold is reached and so you've got that kind of state management mechanism built in there to go and do that the data fetch so that's that's really nice and then to bring it into our react system we're just going to build on top of the state that we had before in this case we're going to use context but we're going to have that state machine using the use machine here and we're just going to return out of that custom hook seconds where we get the context from the state machine names where we get the context from the state machine we're going to set that running value based on the state value so based on whether we are in the stopped or started state and then the on toggle is just going to send an event to that state machine it's a really nice way to encapsulate state when you have those discrete states so let's go take a look at another more complex example this would be like a media player it would start in the pause state you'd hit play go to playing hit pause go back to pause you'd have fast forward and rewind and then those states i would be in a fast forwarding state and then i'd hit play again and i'd go back to the playing state and this is actually this graphic here is from the x-state visualizer and you can actually have it in your running code in development mode so you can actually see your state machine or state machines going from state to state state as you're building out your code it's really cool stuff so let's keep building on our mental model so every application is probably going to have a router to deal with the routes it's going to have some sort of mechanism to go and get some data maybe react query is a good example of that or apollo client and it's going to have maybe a forms manager if you've got some complex forms in your application and i get a question a lot about is that enough for my application and it's a great question and in all honesty in some cases it might be and i'm calling this model api plus essentially adding on a router a data fetch mechanism like react query or apollo client the hook form on top of the state management and context hooks that you already have might be enough for your application so let's go and check out that as an example over in our code okay so this example is over in the api react query directory within examples and we've got our hook that we've just now modified a little bit to add on use query and this is the react query hook so the really cool thing here is that we have this use query it knows how to go and fetch the data but it only does it when seconds is greater than 2 which means that the use effect that we had before that was monitoring the seconds greater than 2 is replaced by just this little expression right here which enables use query to run only in certain circumstances and then i've also brought in use interval from a library called react use and use interval is just a nice wrapper around intervals that makes it just very easy to use and so the total size here of this code gets really small all right let's jump back to our metal model and so why would i use the api plus model well if i have an application that really doesn't have that much complex client-side state might just be a bunch of forms and some data display then honestly this api plus model might just be enough for that so if that's the case then you might just want to just stick with just that it's an absolutely valid way to go now i did kind of jump over context here which is actually really important because when you think about it a combination of routes and api tools and forms plus some basic state management tools like use state and use reducer plus context and you might have enough so let's go back into the code and check out the drilled props code but done with context so here is the hooks context code it's in the hooks context directory and it's exactly the same hook as we had before but now we're also going to create this context so up here we have create context we give it that application state we initialize the context to have seconds 0 running it false and a kind of placeholder on toggle this will never be used but we need it just to satisfy the api and then down here in application context provider we as a component and it has an application context.provider in it you give it a value that value is that hook and then to get the context we create a new custom hook called use application context that has a used context of the application context that we just created and so what this does is essentially just make that hook global and a much easier way to do that actually is to use the con state library and there's an example of that as well in hooke's con state basically just does that but very cleanly so let's go over and check out app.tsx and see how to use this we're going to bring in the application context provider we go down to our app and we wrap the whole application in that context provider then we remove all the drilled props from timer display timer toggle and names and then we replace that essentially internally with calls to our hook which again is essentially global because it's contextual and that's going to give us our seconds our running and our own toggle just like we had before with the original one now we just don't have to drill those props all the way through all right let's go back to our mental model and talk about why or why not to use this context style so why well it's just easier you don't have to do the prop drilling but why not well one of the things about context is anytime you change the value of the context so setting seconds or whatever it's going to re-render everything from that point in the context down now there is going to be a selector for use contacts coming out in the react core apparently soon but it's not here right now there are libraries that allow you to go and do that a lot more easily to just select parts and pieces and you only get kind of incremental redraws but that can be a problem if you have a very large tree with context at the top where that context is changing continuously all right now let's see where our global state managers fit into our mental model so there are four discrete flavors of global state managers that i found and the first one is reactive state managers so what's that about let's take our example application and let's talk about how that's going to work with a reactive state manager so what's going to happen is you're going to hit that start button it's going to send an event to a store we are going to be subscribed to that event so that when the store alters its state that running state based on that it's going to fire off that subscription and we're going to get that button update and then timer up here is going to be listening for changes to that store and then when it sees that it's in the running state it's going to be sending off events to that store to go and update its state and so the big deal here are all these events these subscriptions these events it's essentially a pub sub model and a lot of these are based on rxjs and the one that we are going to be looking at akita is also based on rxjs okay so over here in our reactive akita directory we have four files that are interesting to us the first one is the stopwatch store so this is the data holder in our akita model and we have to specify an interface for that this is all done in typescript so you're going to have a seconds there's a number running below names we're going to have a function that creates that initial state and then we're going to have our class which has the initial state and manages that state and we're just going to instantiate that into a stopwatch store and then there's two things you want to do with any store you want to be able to query it and then be able to update it and so the query part is in stopwatch query.ts you can see that we're grabbing the stopwatch state in the stopwatch store and then we create a new class called stopwatch query that has extends a query of that state and what it does is it creates a bunch of essentially rxjs subscribable member variables and then to get access to those we first instantiate that query and then we use observable hooks which is another library that essentially fuses rxjs observable subjects with react so in this case we're going to get seconds by looking at the current value of stopwatch query seconds and default that to be zero now over in our app all we need to do is just use it just like we would any other off-the-shelf hook and then when we want to actually toggle stuff that's when we use the service and the service in this case is a stopwatch service it's not descending from anything and the really important one here is update and you can update parts and pieces in this case when it sees that we are updating the running state we are then going to go and create that interval and that timer and we're then going to send ourselves updates to the seconds and away you go so everything is loosely coupled and based on events so let's jump back to our mental model so why would you use an event-based store like akita or effector there are a bunch of these different libraries well if you like that event-based loose coupling model one of the great things about events are that you publish them and you don't care if there are zero subscribers or an infinite number of subscribers it doesn't matter so every part and piece of that system essentially just kind of takes care of its own thing and that's a nice loose coupling model this is also a really good model if you're using rxjs already most of these are based on rxjs and they make it really convenient so the next big conceptual bucket of state managers are atomic state managers the two big players in this space are recoil from facebook and daishi kato's joe tai so how does this work so what happens is you've got a set of atoms here so you've got a running atom and that's going to store the value of whether you're running or not and you've got a seconds atom and that is going to have the count of seconds and to just connect to these things you just set that atom there is a hook to do that and you also get that atom and that gun gives you the ability to manage like for example that start button you can also create connections between atoms which is really cool for example like this timer atom can set that seconds atom which in turn does that get and you can also get the value from this running atom over here and you can kind of create a cascade of atoms so again nice loose coupling here and that's an excellent part of this pattern so let's go over and check into our code and see how this is actually going to get implemented in recoil all right so we're over in the atomic recoil subdirectory within examples and that's where you're going to want to go look if you want to go play with this yourself you can also look at the atomic jota variant it's excellent i'm a huge fan of joe time myself so what we're doing is we're bringing in from recoil atom and selector and then some react hooks and atom is our basic unit here so for example we create and store the name value in a name values atom you have to give it a key you don't actually have to do that in joe type you do here and then you give it the current value so this is going to be the list of names so it's a string or undefined then it's going to start it undefined we also have the value of seconds again key of seconds here with a default of zero and then we got another one which is a selector which uses the seconds and the names and what it does is basically say okay well i'm only going to give you names if the seconds is greater than 2.0 there's a little bit belt embracers because we don't actually go and fetch the data until it's greater than 2.0 but it does show you the ability to connect atoms together which is really kind of cool so you got your basic atom values here and then you've got a selector which sort of binds those two things together but you can still look at the names atom just as you would a regular atom so you kind of interact with them the same way you don't know that it's a drive value but it actually is it's really cool so how do we integrate this atomic stuff into our react system well we're going to do that within the context of a custom hook so just as we would use use state you can instead use use recoil state and it's basically just a global element so in this case we just reference that seconds atom it is a global atom and then we get seconds and set seconds and you can also just get the state or you can just get the value and you can use it just as you would with any other use state as part of a use effect for example in this case we're going to do again that seconds greater than 2 thing and we're only going to fetch the names.json if the value of that atom is greater than 2. does it matter that it's an atom no it's fine it's totally fine so how do we use this over on our react components we'll take a look at app.tsx see how that's done from recoil we bring in recoil root and we have to wrap the entire application in that but after that we can just use use recoil value and use recoil straight directly in the components if we want to for example we do that with a seconds here and then you can use use stopwatch we do that at the top level and what that's going to do is just drive the mechanics of the system so if you're interested in this atomic model of global state management be sure to check out the atomic jotay directory as well i covered recoil here because it's the more popular of these two libraries but i find for my money i prefer joe tai over recoil i think that joe tie actually has a lot more cool stuff baked into it for example atoms that can be using xstate or immer it's awesome so let's go back to our mental model so why should you choose an atomic state manager over a reactive state manager or the other state managers well if you like that loose coupling but you don't necessarily want to use something like rxjs i think the atomic model is excellent for that so if you're looking for that really good loose coupling that essentially still has that eventing model built in but it's very lightweight recoil joetine these are excellent choices all right let's continue on with our mental model and look at unidirectional state managers which includes of course the big one redux so what is the unidirectional model all right so we hit the start button that dispatches an action to the store that then changes that running state and then that updates the button and that's the unidirectional data flow in a nutshell everything goes in one direction and then other things for example this timer can dispatch actions to the store that store gets to decide whether it's going to update that stopwatch value and if so then away you go and it's just a very clean model and there's so much in terms of an ecosystem around redux in particular so let's go take a look at how this is implemented using redux toolkit all right so over here in the unidirectional redux toolkit directory in the store file we are bringing in redux toolkit which has configure store create slice as well as create async thunk so what redux toolkit is is it's a library that wraps redux makes it type safe and also reduces a lot of the boilerplate and that's why a lot of people like it so in this case we are going to configure a redux store that's all the way down the bottom here we're going to specify our reducers we have two reducers we have one that manages the stopwatch that includes the seconds as well as whether it's running or not and then also the names and those are most implemented as essentially slices so you can have a store that has multiple kind of self-contained pieces now let's just go take a look over at the stopwatch slice up at the top so we're going to use create slice to go and create the stopwatch slice it's going to have the seconds and the running and some reducers that just set those values in comparison to old school redux this is amazingly simpler now down the bottom of the file we export a lot of the stuff out of this module for example toggle which is an action on that stopwatch slice as well as the selectors which select the state from various parts of that store and then finally we have the timer down at the bottom which is dispatching those increment methods and also when seconds is greater than two then dispatching the asynchronous thunk of the fetch names and all of that is just made so much easier by redux toolkit so let's go over and take a look at the app and see how to actually consume this so right up here at the top from react redux we're bringing in the provider as well as use dispatch and use selector which are the standard redux hooks and then we're bringing in our store our toggle our selectors down here at the bottom we're doing the provider and giving it the store and then let's just say over here in timer display as an example we're using use selector straight out of react redux and getting back seconds so we can see that redux toolkit doesn't change how we use our redux stores it just makes them so much easier to create which is really valuable all right let's go back and take a look at our mental model so why is a unidirectional state manager like redux or zustand first i think the mental model is actually a lot simpler than other state managers so there's that there's also a huge ecosystem around redux as well as a whole lot of people that know redux so it's still a big contender in the react state management space all right let's finish up our mental model of state managers by taking a look at bi-directional state managers which are exemplified by mobx so what is that model well pretty simple you start off with a plain javascript object that may have the seconds and running and a couple methods on it you then hit that start button and set for example that running value or call a method within set it and then because that button is also an observer of that stopwatch object it then gets updated somewhere sort of thing with your stopwatch count over here it's also an observer and so whenever that changes then it gets automatically updated and the stopwatch object is free to do what an object itself might do and create timers and then set its own values and it just all works so why is it called bidirectional well if you set the value that's okay and then if you get the value and you're inside an observer then you'll automatically get updates whenever that value changes it's just a very very simple flow let's go take a look over in the code and i'll show you just how simple modbx really is so in the bi-directional mobx directory over in the store file we have application store and all application store is is just a plain javascript class it has javascript member variables like seconds running and names those are all just standard the only thing that we connected to modbx with is we do this make auto observable and that makes any instance of this application store observable and it doesn't necessarily need to be mobx observed it can be observed by anything but mobx makes it easy to do that connection as well to react so there's also on toggle which is a an action because it's a method of that class and then all we need to do to instantiate the store is just create a new one and export it as the default now over here in app.tsx we use mobx react lite and get the observer and then we then wrap all of our components that look at particular values within that store in that observer and then all i need to do to access data is just say store dot seconds as an example or run a method on that store.on toggle and it all just works the only concessions that you're giving to mobx in this model is the make auto observable up here and then wrapping your components and observers down here so it's just a very easy way to model a store and have your ui update dynamically based on changes to that store so if you're really interested in this model but you think that mobx might be a bit too heavyweight even this light version you might want to take a look at valshio again from daisukato it has exactly this same bi-directional two-way data binding system and there's an example right in the code bi-directional valio and you can have a look for yourself all right let's go finish up on our mental model so why go with a bi-directional model like mob x simplicity there's also some great tooling around mobx mobx in the react ecosystem has been around for a long time and has a great community around it so it is definitely a legitimate choice when you're looking at redux versus mobx there's also some excellent ones like valcio and eg state which make it just that much simpler and of course all of those are also included in the github example code all right let's finish up with our mental model and i hope this helps you categorize the different types of state management mechanisms and figure out which one is the right one for you now there is one more thing to consider when it comes to your choice of a react global state management model and that's whether it is in fact truly global meaning outside of the react context so you've got react local state that would be the state within a component you got react global state which means global to the entire tree so that probably means something like context and then you've got outside of react itself meaning code that's actually executing outside of the react context so in some cases for example global state hooks you're going to be restricted you're not going to be able to get access to them from a global source whereas in the atomic unidirectional and bi-directional models most of those you can dispatch externally for example when it came to the redux toolkit we had a timer that was external to the react context and we were just firing events into the store and it wasn't a problem in some cases it can be so you want to make sure that if you need global access that the global state manager you choose can support that now i do want to emphasize one more thing and that's around the portability of business logic so here's our application we may choose for example a unidirectional data model and we've got our api in here or we may be using just the react hooks mechanism which is fine but if we have some sort of complex business logic i want to really encourage you to make sure that you externalize that into its own mpm library maybe in a mono repo so that it can be independently testable you don't want to get business logic tied up too much in code that is directly connected to react so you have business logic tied up in your use day use reducers use effect and so on and so forth if you have business logic that you think might ever want to go into a server or go into a different system you're going to want to make sure that that's absolutely externalized so you can 100 test it outside of the context of react you just want to make sure that the concerns are separated so you're not mixing your ui logic and your business logic to the point where you can't decouple them later all right let me answer the question of what i would personally use when it comes to state managers as of 2022 and we'll start off with what i would use professionally now professionally i have would have to add on the concerns of who is available to do the work as well as the ecosystem around the libraries which tends to skew my decisions a bit more traditional so in this case i would strongly prefer to do an api plus model where i'm just using react router react query apollo client one of those react hook form and keep it very very simple as always i would externalize the business logic if there was interesting business logic that i would want to be able to reuse in different contexts when it comes to having a global state manager i'd probably still queue towards redux using redux toolkit again because of the number of people that are available to work on that and also the unidirectional simple data model and all the tooling around that or if i want to go with a bidirectional model modbx is also an excellent contender in here and still has a fantastic support community around it now what i would use personally is very different because it's just going to be me and when it comes to global state management i do tend to prefer the atomic state model like joe tai i just really enjoy working in that model as well as the bi-directional model using valcio it's just like mobx just as powerful but it's just a lot smaller and lighter weight easier to use at least my opinion obviously modbx is also very easy to use these are just my personal preferences obviously your mileage may vary all right well i really enjoy doing all the research i hope you check out that github repo and check out all these different state managers for yourself if you have any questions or comments be sure to put those in the comments section down below i can't wait to hear the comments on this video and of course in the meantime if you like this video hit that like button if you really like the video hit the subscribe button and click on that bell and you'll be notified the next time a new blue collar coder comes out
Info
Channel: Jack Herrington
Views: 69,328
Rating: undefined out of 5
Keywords: 20 react state managers, effector, jack herrington, jotai, jotai react, mobx, mobx react, react query, react state, react state management, react state management 2021, react state managers, recoil react, redux, redux toolkit, rematch redux, state management for react, state management in react, typescript and effector
Id: P95DuIBwnqw
Channel Id: undefined
Length: 35min 18sec (2118 seconds)
Published: Mon Jan 03 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.