David Khourshid - The two types of state management

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
and please welcome David all right hello everyone so I was going to talk about use effect like I've been talking for the last few months but if I just installed react to produce stress then you know I wouldn't have had to talk about it at all use the fact is terrible don't use it that's basically all of my talks but now we're going to talk about two types of State managements and honestly use effect is not that terrible so uh my name is David corsied I'm at Stephen key piano pretty much everywhere online and uh like Sarah said I'm the founder of stately.ai where we think about State Management all the time so uh there's a lot of choices for State Management out there today like Emer Redux X Tate which I maintain mobx Joe Tai recoils duston rxjs the list goes on and on there's so many choices so my goal here today is to help you choose the best state management and I promise I'm not biased at all even though I created X state so uh what we're going to talk about this and I'm going to help you make a decision based on your needs right so first of all why do we have State Management in the first place and uh the reason is because before we had Singletons and we had Global mutable States and we all decided that Global State and mutable state is just a really bad thing but have you thought about why it's a bad thing well the thing is that mutable State isn't actually a bad thing not at all in fact none of our apps would work if we didn't have mutable States it's shared mutable State that's bad and the reason it's bad is because with shared mutable State we have accidental complexity leaking in it's because when you have something that could be mutated from multiple sources now you don't know what is updating what you can't isolate your logic so your code becomes very hard to understand and it becomes very messy and your tests fail for no reason so and also on a technical aspect react Works Within edible seat because it's using referential checking to see should I update this component or this part of the component like basically should I do a re-render and so when you have mutable State the references are the same reacts can say oh okay yeah it's the same object and so that's a problem so getting that out of the way shared mutable state is the root of all evil and this is what causes accidental complexity in our code base so again you know mainly because of reacts but also because for developers it makes it really hard to understand our code so um we could actually experience a lot of these problems with accidental complexity even when we adopt better State Management strategies so uh all of these State Management libraries including you know just react itself if you're using uh the normal State hooks are subject to this complexity and they love to use counter examples because that's the simplest thing you could do right so um let's start with the use date hook this is a very simple counter example and if you are a lucky developer working for a company that all they do is make counters then you're set you could just use reactokes you could use State all day long so we have you state you know we have set counts where we could increment the counts and decrement the counts and this is as simple as you could get in react so why do we need State Management Solutions why do we need any of the other hooks well it's because our requirements are never as simple as this let's say that we added a very simple requirements where we wanted to only counts between 0 and 10. okay so now we have to add a few things and because I put my logic in the event handler I'm just going to put the uh the conditions right inside of there it still doesn't look too bad I could still fit it on one line unless yells at me and then I have to make it three lines because I need those curly braces for no reason whatsoever but now there's uh there's a problem because um you know I I might want to increment it and decrement it in other places so it's a good thing to just move these into callbacks up here and uh you know if I'm super super um you know cautious about performance I will wrap these and use memo thinking that it will give me better performance spoiler alert it will not or at least it will like a very minuscule amount and you're going to increase your memory usage so performance or balances itself out there and also look down here some developer on my team decided to add an input where I could change the state whenever I want on blur so when I increment sure I won't be able to go above 10 when I decrement I won't be able to go below zero but now you know if you just type any number in here you uh you could still go above 10 below zero and yeah so let's fix that problem we could just put everything into change counts and I forgot to highlight these but now when we change counts we are ensuring that we're only setting the counts to a value between 0 and 10. so did this solve our problem not really because we still have this set count variable available and if you take it out of there then you know another developer might just add it in so you're still culpable of um you know just introducing impossible States in your app so um let's get a little bit smarter about this very simple counter example and let's actually use a reducer you know that big nasty hook that we sort of as chew for use date which is actually really useful because it does give meaning to uh how we could update our state so now I could clearly see there's three operations I could do I could increment decrement set my state and I could also ensure with this cool little math.math.max that it stays between 0 and 10. no matter how high or low of a number I set and then over here all I have to do is send and use an event object and just send it over by the way if you didn't know about e.target.value as number really really useful stop trying to cast your strings as numbers from events you could just use valueless number it's extremely useful all right so use reducer it is useful but now let's say that we want to share the state with multiple components so we would use context so we would first create a context and then we could read the counts from this context because we're passing it into a context provider in the value down here okay simple enough you know we just hoist this to the top of our app so that we could use it in our components and um now we actually don't have a way to send events to it though so we can't really increment or decrement so that's a little bit of a problem okay so let's uh let's bring that in too so now I'm also passing in send so I actually have that send along with the counts so what's the problem here I mean we have counts we have send we could share with all of our components well if you've ever done any sort of State Management with context before you're going to get bitten by the fact that components are going to re-render unnecessarily so instead we're going to set up some sort of subscription because we don't actually want our components to re-render we want to subscribe to the values from the components that actually care about the counts so we're going to have some sort of store that we make we could subscribe to that store and we still have our send function so we could send events to the store and we're also keeping the state up to date just by subscribing to that store and whenever we get get accounts we're back to our good old friend you States in our components so this ensures that only the component that cares about the counts actually re-renders which is great but then there's another problem and that's you know let's say that we have a component that only cares about even numbers or only cares about if you're at the lowest or the highest value so instead we need to have some sort of selector mechanism because we want our components only to re-render when the specific States or derivation of state that we need in the components uh you know is what we expect so uh right now I'm just Reading Counts but you can imagine this transforming to whether it's even or odd or Min or Max or something like that and you know we have a small little U selector hook that's just making sure that we are only saving the state of you know the whatever we're selecting and so with all that's we've solved our problems and we've recreated Redux you know the thing that we tried to uh move away from so that's uh that's one of the problems of State Management when you're using Hooks and so I'm sure that anyone who's worked on an application complex enough knows that hooks are really not sufficient for more complex and just I'm not talking about like really complex State Management but anything more than a trivial level of seat management and so that's why we have a whole bunch of State Management libraries and I've separated them into two rough categories so some are used date-like where we're directly manipulating States and some are use reducer-like where we're indirectly manipulating states by dispatching events or actions as it's called you know in Redux um but let's let's simplify this even further so instead of it being used in the use reducer like we have direct and indirect ways of managing this date so let's go through a few libraries and see what the landscape looks like today uh first we have recoil where we have this notion of atoms and so this is one of the direct ways of updating States uh you would just um you know set text you use recoil state so it feels very much like use States and you could just manipulate it from everywhere there's also a vault here which is uh not not really exactly the same you have this you know uh global-ish States you could use the snapshot of the state and you could directly manipulate that state over here it's using uh a proxy to just uh maintain observers in the components so that it's only going to re-render when um you know for for the things that are actually reading the states uh there's also mobx which you know has been around for a while and so with mobx it does have the notion of these actions like increased timer but at the same time you could still just directly manipulate the state and it's going to cause your component to re-render uh when the State updates so we could see that down here we have my timer dot increase timer which can feel like an event but again you could just directly manipulate the state two and get the same effects and there's also jotai or yotai I'm not sure how it's pronounced but this is very similar to recoil where you have atoms and you could just read the atom and just you know of course manipulate it from anywhere you have this set text for instance so it feels very much like recoil and so these are the direct State manipulation libraries or at least some of the more popular ones that I've seen so now indirect event based there's a few options to choose from there's Redux and the example is actually pretty long not as long as I thought there's Redux toolkit which actually makes your old school Redux a lot simpler and I do recommend using Redux toolkit if you're coming from Redux you know you have your reducers your slices and you would send events so you grab this patch from use dispatch and then and highlight it here but you just dispatch events in the State updates and you could read the state using selectors there's also zastan zushdant I'm terrible at pronouncing State Management names uh but it is sort of like Redux where instead of just having different actions you have these functions over here and you read set and then you could just um you know set the state within those actions and you also have um I guess a selector mechanism over here these create a a hook which is pretty cool so you have used bear store and then you could just read the values that you care about and your components will re-render uh you know when that value changes and so you could just um grab the grab the accent in the same way that you read the states and uh just uh you know manipulate the state that way it's still an indirect way of manipulating the state because I think you can't really like directly change for example the number of fares you have to either click increase population or remove all bears which sounds very Grim Bears aren't that bad and of course there's also X date so exit you create this machine definition and honestly like you don't need to think in finite States in nested States parallel whatever you could use xdate pretty much the same as you would use distend or Redux where you have this context with data and then you have these um you know these transitions where you could assign to context so you know you could add one subtract one and then you basically have the same mechanisms where just like use reducer and Redux and zustin you could indirectly manipulate the state by sending events so uh there's also local versus global but all of the libraries I mentioned are Global capable which means that you could use them in a global context and basically read the state and uh you know manipulate the state from anywhere in your react tree and if you wanted a more local solution then that's where you state and use reducer would come in handy there's also multi-store versus single store and I know that Redux insertion may be at maybe um the decision to have only a single store just because it's um I guess easier to implement you have this single source of Truth whereas you have multi-store Solutions including X dates where you could have multiple stores which means that you could use these bits of State at any level of your application and you could have different concerns for different parts of your app whereas with Redux insertion you have this idea of slices where um you know different slices would pertain to different responsibilities in your application so uh you know they sort of more adhere to the single source of truth but one important thing and this is you know I'm going to mention a few important things in this talk but one important thing that I want you to know is that single source of truth is actually a lie there is no single source of truth in your app and the reason is because data your state lives everywhere and so um you know you have to just be able to read this data from everywhere you have different things that you're communicating with whether it's the Dom whether it's some graphql API whether it's some separate service or some separate Library there you can't assume a single source of Truth there's also effect management which I'm not going to get into different State Management libraries have different ways of managing effects but the other important thing I want to tell you is that effect management is State Management so instead of just thinking in terms of when I have an event that comes in this is the next date that we get it's important to think about what are the effects that happen as a result of my state transition or as a result of the state changing due to the the event there's also two types of performance optimizations that libraries typically do whether it's selectors which I consider a manual approach doesn't mean bad it's just manual and observers which is more of an automatic magical approach so that's another consideration to keep in mind so um you know I have less than 10 minutes left so I'm going to summarize a little bit we've talked about a few things directs versus indirect single store versus multi-store effect management performance but none of this actually matters and and these aren't really the things that I want you to think about when choosing a state management solution so what are the important things well the first thing is correctness you want to make sure that your application logic is bug free accessible doesn't have race conditions adheres to specifications and is verifiable which means whatever user stories you're handed from your PM does the logic actually match that and is it going to introduce bugs or prevent bugs also velocity whatever solution you choose are you able to add change remove features quickly without removing bugs are you able to onboard your team quickly so that they themselves can add features and make changes rapidly and also maintenance like how well can you map your application logic to documentation performance uh how could you you know better test your application logic do you have a single Source um where you could just isolate your logic and actually uh unit test it integration test it and all of that so those are the three things and so that's why you know I haven't really talked about State machines yet but um I one of the reasons that I love State machines is because State machines allow you to express both the specification like this user story over here and allow you to go more into detail and refine the parts of your state machine with actual implementation logic and so you know that's why I created X dates and so that's why um in helping you deciding which state management is best for representing these kinds of flows the real answer is the one that your team is the most comfortable with right um I I don't mean to say that xct answers you know not but like uh we've been working on X date um and we have version five Alpha that's you know hopefully coming out soon and so we've been thinking about these problems too and uh one of the approaches that we're going to take is making X8 version 5 a lot simpler to onboard and also a lot more flexible so that you could interpret more than just steep machines like promises observables reducers and callbacks and this has the benefit of you being able to visualize your entire application uh architecture like just how each of these parts talk to each other and even generate more visuals like sequence diagrams and also xdate works with a bunch of different libraries too and this is one of the reasons why I've been thinking about these problems a lot and you don't really have to choose between different State Management libraries because XCX more like a state orchestrator rather than State Management with all these libraries and two mystery ones that you're not I'm going to see because conference Wi-Fi sucks so in general the way that we typically code applications is the easy way you know we have logic and event handlers callbacks and ad-hoc logic just floating around we have simple ways where you know we would just separate our application logic into reducers and maybe combine those reducers and this allows us to have a simpler understanding of how everything works because everything is just in events and then we had you know a simpler way where we could better organize the logic within our reducers but of course this isn't really easy it is a learning curve to use State machines and uh when your app gets really complex that's when State charts come in and that's definitely not easy so um overall it doesn't matter like what you use what I really want to emphasize is that your application logic and the logic your view logic are not always the same in other words the data flow tree is not the same as your UI tree and it's just really good to keep those two things separate so this separation can be achieved really with any State Management Library basically you're separating your user interface from your store and so you would send events to your store saying the user did this thing or this thing happened and then from your store you're just reading State and that's it I mean there could be a lot of complexity in the user interface there could be a lot of complexity in the store but you could save yourself and your team from failing to understand The Code by separating those parts of complexity and having a very clean way of communicating between the two so um you could map your requirements to code like this is what I would suggest for whatever State Management solution you choose uh basically have a very clear mapping of the user stories to code code in a view agnostic way even if you don't plan if you don't plan on changing State Management libraries or changing Frameworks or anything just code in a view agnostic way it really helps you enforce that separation make your views dumb we've heard about smart and dumb components make all of your components done because your components should just be things that read State and that send intentions from the user to some store or stores whether you're using single or multi-store and then literally profit because what I mean by profit you know and I'm thinking about this especially as a founder of a startup is that the the important parts of code are not really just how fast it is how much es lints likes our code whether it's in typescript or not but it's really the value that we're providing users are we able to ship features fast are we able to create intuitive user interfaces and are we able to maintain the code so it doesn't take forever to add new features and this works with any State Management solution so of course there's a bunch of important things but I feel like these things are important on the right hand side and overall just make it work make it right and make it fast and um you know you're just going to have a better time uh you know just managing your state so in summary there's two types of State Management there's simple State Management where your code becomes very easy to understand no matter how complex it gets and there's easy State Management where your code is very quick for you to get up and running uh you know just putting the logic in there manipulating State wherever you want without any care of how it maps to application logic so which one will you choose thank you react inland [Applause]
Info
Channel: React Finland
Views: 3,215
Rating: undefined out of 5
Keywords: react, react finland, paasitorni, react.js, finland, conference, javascript, web development, programming
Id: JevYDCy5HzA
Channel Id: undefined
Length: 23min 23sec (1403 seconds)
Published: Fri Oct 21 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.