You still use Redux?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
there's a lot of different ways you can think of state types but i'm going to break it down to a couple specific ones uh server state and i think i'm going to break down to server state and client state ta-da see magic all we have here is on blur run the mutation and on that success or on that mutation success revalidate the query this is an overdue rant i think that react state is a topic that generally we worry about a lot but don't discuss solutions about enough i feel like everybody's really eager to shout about their favorite state manager and not about the like more fundamental problems of what is state and why are we building it so this is the react state management rant and i want to start with a really important callout if you can use react query you probably should this is important to understand a lot of state management isn't managing state in the sense that these are things that can and often change and that user interactions like live manipulate and mutate traditionally when i am talking about state management with react engineers what we're discussing is state synchronization between the client and the server the goal isn't so much to create how do i put it it isn't to make a state machine with all of these events and actions and behaviors so much as we have data on the server the client requests it and then the server gives it to the client and the client has it now the so many state problems are that and i've seen a lot of people reaching for state managers when what they're looking for is a way to synchronize their server with their client so please i implore you if you haven't used react query yet and you're looking to install redux or sustander one of like the many other things we're going to talk about please read the react query or the practical react query guide by tk dodo first this does a fantastic job of breaking down the idea of client state versus server state in the things that react query is good for if after this it still feels like it's not the best solution and there are edge cases in here even like the using websockets with react query might be a bit of a stretch for some but at the very least understand this and how synchronizing your back end and your front end is probably what you're looking for most of the time with state and pick a solution that's good at that first with that all said let's talk about state in the different types of state so what is state data usually data that can change state is a a very general catch-all term can be the things in your ram it can be the like objects that react has access to it could be the use state calls it could be a lot of different things but generally the idea of state in any given application layer are is the things in that application layer that can change what are the different types of state there's a lot of different ways you can think of state types but i'm going to break it down to a couple specific ones server state and i think i'm going to break down to server state and application client state so server status things like the user's profile like how many or what's the user's name how many people are they friends with what are the current profiles that are on twitch like who's live right now those are server state things that the server has decided and described in a specific way server state is what most of our job is to deal with it's taking things that are on the server and displaying them to the user in a way that is a good experience for the user but also often that they can interact with and modify the server state application state is things that are specific to the application in at any given time things like which page are you on right now is your microphone on or off do you have a video device connected so a good simple example of application state would be a a use state for keeping a menu open and closed whereas a more common server state example would be const data loading or is loading equals use query data fetch some data french gonna do uh poor uh maple's favorite here can i get enough parens there one off cool right so server state is data that you're fetching or getting from somewhere else that you're then showing in your application so another way you might look at this when i first write it is oh well application state is things you can change and server state is things that you can't so you should probably use application state for anything that the user might want to edit like are you fetching your bio on twitch for example can you just edit the text if you're fetching it from server no you're going to have to put that in state right well let's think about it for a minute we could we could use the data we get from server to pre-populate the field in pre-populate state const data equals use query i think it has to be an array now some query and we'll return default state and this is the thing that we get back from the server actually rename this to server state i'll i'm going to use a little hacky way pretend this code is on the server let content equal default state and we're going to return content here so again pretend this is on a server and then everything here down is client so what we're going to be doing is operating against this external server state inside of our client so now we have this data i can input value equals data and can i find oh it just died and now i can use react query what i was doing there was creating the context that is a single context for all of react query so we'll never have to think about it again really convenient that we have to do this once knowing we have to do it once but once it's done no more contexts no more of the global chaotic contact stuff so from here i want to use this data right now we're putting it as the value here but that's not great because when i change this if i keep typing it doesn't let me because the value's hard set i have no ability to [ __ ] with this so i can change it to default value i think it's just default oh no that reload kills all the things i did i'm gonna be so mad okay so i changed the default but it's not there at all if i put another string nope i guess default just doesn't work a default value is a thing that's what i thought cool now we put data here instead i actually think that would work so i didn't think this would be loaded in time uh is this immediately loaded because it's a function that can run immediately console.log re-render with data data now it comes through undefined initially interesting so if you change the default value okay that's what i thought would happen so here we have a different default value of like please fill this in and even though our code says use data or please fill this in we always get the default of please fill this in the reason is this code decides on the default value on the first render when we don't have data yet because this is a query this is coming from the back end however we want this to be correct so the quick simple and i would argue the best fix for this would be in is loading here and return some type of placeholder in the interim so if is loading return div loading and now this will always load the state from the server because this item does not render until the server has given us back data and this is populated because is loading this check here will prevent that from rendering so the default value we get ends up being correct in the end now you could also use a key to force a reset but that would have other potential side effects so now the question is how do we change this like i can write values in here but it's not affecting anything clearly i have to go at a state pull the data from the state modify the state and then post it kind of think we can do a lot simpler here so first we need the used mutation that will actually do this so const mutate equals use mutation this doesn't need a name if i recall so i can just do this data content equals data so now when we call mutate it will set whatever we pass to it to be this content value but let's say we have another thing rendering this below so we have a h1 current value we want that to be data so we have this but i'm changing this nothing's changing we want it to i can add on submit e for the event and we want to e dot target actually don't know if onsubmit will fire on enter i suck at forms i'm going to do this the easier way of a button we don't want it to fire on change because we don't want to fire the mutation constantly i think on blur might be the best thing so we'll start with on blur just because it's easy and on blur we're going to mutate e dot current target.value and now i'm going to change this and nothing's going to happen still because this data isn't refetching we're changing that but this is a server value we changed we just posted effectively to the server saying hey we're changing this value and the server's like yeah sure thanks and then doesn't do anything else what we need is and on success we want to do something in this case the easiest thing is refetch that's not what i copied and now oops wrong button tada c magic all we have here is on blur run the mutation and on that success or on that mutation success revalidate the query this might be a it might feel like a tiny bit more code than writing your own state management however it is significantly less bug prone and you've reduced the dimension of problems we no longer have to worry about the relationship between the input the state and the server because the relationship is when you leave the input that becomes the server state and when that change occurs things are revalidated somebody asked the question of does this also invalidate the cache it does the cache will get updated as well you also have the option instead of doing it this way where we immediately revalidate this with the refetch we can instead use the query client so query client equal consequence equals use query client and in here we can do qc dot invalidate queries pass it some query which is just the string name from here might have to be in an array for that to work let's test it that did not work might have to be double wrapped no validate queries huh interesting i don't know how the new invalidate queries works this should absolutely be working though oh it might be because it needs the like undefined maybe it doesn't need either interesting yeah i i'm not sure why this isn't working here's this be null yeah i'm actually not sure why this invalidate queries call isn't working this should absolutely be fine am i getting console warnings unexpected token expected comma that was not from this was it i want to set up the react query dev tools but that's not trivial inside of this sadly [Music] [Applause] [Music] installing this but the package isn't resolving correctly it seems like v4 is just kind of [ __ ] right now so we're going to go back to 3392 there we go what is this upset about oh this needs to be a type there we go does this need a key limitations didn't need a key what is this upset about why am i getting unknown to hell did i just kill the typescript server yeah that's what happened it knows the type whatever okay we're gonna just go with it from here i should plan these things ahead if i want to do them with like an example that's working we have some state that is on the server the server is imaginary it's this variable but we're not letting the body access it directly so in this some query function pretend that we're fetching data from the server in this mutate function pretend that we are sending a post request to the server to make a change on that side so the on success case here we are invalidating the query to be or because this value is new and the query should now be refetched to have that data but not necessarily in some cases that's not the best path forward like the server might take a while to return that data and you want to have that change on client immediately let's say i make this uh a new promise i haven't done the og promise syntax in a while uh did i get that right ish i think i have to return it yeah i do cool set timeout and we're going to resolve this request with content after a second so now when i load the page it's going to load for a sec before it comes in we made a fake timeout to or a fake request there so now when i make a change so new content it's gonna take a second to update because it's now loading that data in the background if i was to change is loading to is fetching here also is this mad about i guess that it doesn't know the type of what this promise resolves that made it shut up so if i switch is loading to is fetching what's going to happen instead now whenever i make a change it goes back into the loading state because that data is being fetched again but let's say we want to avoid that we don't want to have that time in the back and forth to the server to get new data and we don't want to have the state where things are stale we can instead of invalidating the query qc dot update or set query data and we can set some query to be the new uh the new data that we have here which on success will actually have the data which we don't want what we want is the variables because this is what you submitted with so we can stop calling content because we don't want to call content here we don't know what content is that comes from the server and now we are setting the query to be whatever data that we took in here and that is not working because new data default state is what it's oh no it's getting the right thing maybe the set query data isn't happy [Music] [Applause] [Music] what we're seeing here is we have this content that we're fetching from the server we have a used mutation that is running on the client and once that client mutation has succeeded we immediately show the new value but now i'm going to throw one more wrench into things so now when we resolve this mutation we make the change it also has a one second delay so when i make the change here it will take one second for my changes to appear because we're doing them on success there is one more option you have which is on mutate and this doesn't have data it only has the variables because we haven't finished the mutation yet this is called an optimistic update we are optimistically changing things even if the server doesn't accept the change so if i was to in here instead of returning content return default always will get default initially but then it gets ignored because i'm just overriding that value in the cache with whatever the hell i want to all of these options make sense in different situations for different things you can also combine them with the loading states provided by react query to determine what inputs can or can't be touched at a given time but what you'll find the more you play with it is the vast vast majority of weird state cases that you're dealing with and thinking about can probably be solved very well with react query now that we've talked all about interfacing with apis what about the things that aren't because most things are server state and there's lots of ways that are better than application state to handle making changes to server state server state isn't just things that don't change it's the relationship between the client and the server and how those things change but there's a lot of things that aren't that so what isn't server state i actually get in this argument quite a bit because there's a few people in uh certain frameworks communities that insist that things that are developed in these like new data fetching patterns somehow invalidate the need for something like react query i wholly reject that i think react query is useful for lots of other things that aren't server state like av device management uh navigation state open close menu state it's a lot of things like this uh one that we have a lot in ping is is chat visible or open where like you have a sidebar where it could or couldn't be open and this isn't state that only matters for whether or not it renders this is state that's kind of global because we have a notification system and notifications behave differently depending on where they're being or depending on whether or not the menu is open and the chat's open so if chat's closed notifications pop up at the top if chats open they appear in chat directly or things like ini instantiating the camera device that's an async function that i have to call and then wait for behavior and then get that back react query can do all of these things i would say for the av stuff it's good not great for navigation it's bad for open close menu stuff it's terrible and for his chat open it's also pretty bad so for a lot of these types of very applicationy problems especially the synchronous ones like navigation state and menu state stuff react query isn't the best solution so what should i use instead when it's not ideal so this is going to be a list in order of what you should prioritize so option one should be built in react state use this if it's simple enough to do if you have a used state in one place that you want to pass down to some children so they have that data that's fine don't be too scared of prop drilling i find that a lot of engineers get turned off by the idea of prop drilling so much so that they just don't pass props like ever that's not the solution here at all you state is fine and passing things around is fine as well i should say built and react use state addendum i don't recommend context much context in react is very powerful for prop drilling effectively so if you have some properties that aren't going to change much and you want everything from here down in the dom to have access to those properties context is a good way to do that but if those are values that are going to change a bunch like inputs like user scores or behaviors or chat or those types of things context is the most wrong of wrong ways to do it for things that don't change context is great it is a simpler i should say simpler it's a more complex but more but less boilerplatey code prop drill pipe the reason why you don't want to use context for those things is it is passing everything in it to everything that consumes it so if you have a component that is consuming the if you have a context that has the user object and whenever the user clicks a button it increases the user's score and that changes the user object in the user context now everything consuming that context has to re-render whenever that comes through react memo will not solve the issue it will double the amount of compute you're doing while not solving the issue it's no react or react context is an effective way to say from here down everything has access to this data and everything will re-render when the data changes react context is for dependency injection pretty much nothing else if if you're looking to make passing props a little more ergonomic maybe use context otherwise probably don't touch context so what do you use instead well we're going to draw a diagram so this one's going to have a question in it why didn't use state work there's a couple different reasons why use state might not work for you reason one might be i need a global so you are cool with you state as it is but you don't want to have to pass values constantly up and down everywhere one of the best things to use in react if you state isn't like ergonomically pleasant due to the prop drilling and all the other chaos and you just want to have effectively like a used state that you can reuse in 15 places jodi jodi is fantastic jodi has a system called atoms it's an atomic state manager so the simple examples are like you define an atom by importing atom and then you give it a value and now when you call that with use atom you get the value and a setter and you can call use atom on a given atom in a hundred different places in your app and when one of them changes it all of the rest update no context no chaos just a simple define an atom and then consume that atom in other places you can also derive atoms using their derivation systems they have cool recipes and things like that it's a lot of fun to be had with jodi but generally speaking its strength is i have this thing that i want to change and now it will or and now when i change it it will update in other places so if i so if i had a context that had 15 values in it and any one changes all of the other values or all of the things consuming the other values have to re-render and update as well with jodi you can just define 15 atoms and then whatever consumes whichever specific atom updates accordingly if you had an atom that had a big object in it with lots of keys and you were consuming one key off that then it's still going to re-render the same way context does but if you use atoms to break up your context it's a really efficient way to do things all of that said there are a few reasons why you might not want to use adam and those are the other directions i want to go in here one of them is i need a machine actions events etc so if you have instead of like const count atom equals create zero and then we want to like all right and then we can call const count set count equals use atom count atom and then below here i can call set count five and that just works but let's say we don't want the ability to set count we want the ability to increment count so i'd want this to pass get increment and then we call increment with no argument you can't do that with atoms you'd have to redefine all of that functionality yourself and it's not going to be a great experience to do such so if you want to store i'm going to move this example over here so if you want to store instead this is where zest stand really shines i'll write that below quick before i forget sus stand so in just there is a stand i'll just go to the docs because they're really good you create a store instead of a value so in here we create a store it has bears which is the value in it and then you create actions which are updating events on here they're functions you can call so when we call increase it sets the state to be bears plus one and when we call remove all bears it sets it to zero so when you use something like sustand you are handling the ways you interact with the state as part of the machine so that what others consume it you know which behaviors they're able to work with this is a machine not shared state this is a little closer to context and how it works where you can define different things on it the big difference is you can subscribe to specific values so if i had bears and a different key on here and that other key updated all the time when i select from it so use bear store state state dot inc increase or in this case state dot bears this will only re-render when state dot bears changes with controls this will never re-render ever because increased population is never going to re-render they're never going to change it as long as that function never changes which it won't we're not rebinding it it's never going to re-render i've seen a few questions about other solutions in particular recoil with jodi yeah recoil is pretty similar to jodi jodi is a lot simpler better maintained and more likely to keep doing well i'd probably use that but yeah sustained and jodi are my two go-to's right now because they solve those two different types of problems i'm not gonna bother with a good snippet i showed everything i wanted to there so if your reason for you stay not working is you want something more global go to jodi if your reason for wanting something other than you state is it's not actionable and it's not something you can interact with more directly zus dan's a really good solution it also has some fun magic tricks uh let me reopen the docs here where you can access the stand outside of react which i do pretty regularly there are some examples uh yeah without react so you can call from zest and vanilla get state set state subscribe and destroy and now outside of react you're able to make changes and update things so i'll often bind listeners externally that update the store outside of react and then react magically updates itself whenever those things change it's a really convenient way to do external uh like management of data that is internally operated within so if building react state isn't working should probably go with jodi or sustand i use both at the same time pretty often it's really nice there are lots of other solutions i see people mentioning redux redux was great and it made all of this possible but it's way more work to set up it is way more complex overall and it's a decent bit of code remix redux is very large jodi is 3.39 kilobytes and just stand is 1.16 kilobytes yeah redux does so much more than you need it does all of these things but you probably don't need all of these things almost everything i build needs neither of these it's very rare that i need to reach for these we use jodi for some like global device management stuff in ping like which devices are active and then we use a stand for like the chat room to manage who's connected and like websocket connections stuff like that everything else is react query all the stuff we talked about up here generally speaking most of the stuff that i'm worrying about when i'm worrying about the state in the data of my react application is data that i'm synchronizing from my server so i don't need a state library more often than not when i do jodi and zestand solve the specific problems that reacts built in state were not built to solve so i reach for these two very minimal and light solutions when i need them and i don't when i don't one more option i want to bring up because it is really cool and more people should probably use it for complex things but less people should be talking about it because most people aren't working on those problems is x state x states goal is like proper state machine architecture in the very formal sense so like state visualizers with really complex diagrams to see all the ways things go this is all of the code for a fetch as you can see that's 39 lines of code for a fetch and you have to write your own type definitions on top of it don't use this for store or for like server state don't use this for simple state machines and values you want to synchronize between things use this because you have some very complex custom absurd [ __ ] and you want a diagram that lines up with the machine that you can use to obsess over it i have found very few use cases where this level of architecting your state is necessary it can be very useful but you need to have so much complexity in your state that introducing this makes it simpler to reason about because you are inherently introducing complexity when you introduce something like uh x-state so be be careful when you add in something like this but if you know what you're doing and you know your problem sucks it can work really well trash just mentioned in chat that he likes it but it falls apart with sibling machine communication which means you have like a greater machine and then sub like children machines for different things within your app i do that all of the time with us stand like every single day in ping we have a greater zestand store that is the device manager and we have sub stores for random [ __ ] in the call it all of these things interact by calling functions to and from each other and it's fine the boundaries that we're defining there are usually react itself and using zusdan's context provider as well as like the store instantiation protocol methods that they provide it's pretty easy for me to build a state machine for one thing and have it interact in simple ways with the other things so highly recommend trying other things that are simpler until you hit the limits of them you'll notice that that's generally my philosophy but what you're gonna see here is how i'm applying it which is start with u-state use react query and things like it for the server state side and then when you can't use state because you're running the specific problems with it grab jodi and grab zestand i hope that this helps hey did you know that over half my viewers haven't subscribed yet that's insane y'all just click these videos and listen to me shout and hope that the algorithm is going to show you the next one make sure you hit that subscribe button maybe even the bell next to it so that you know when i'm posting videos also if you didn't know this almost all of my content is live streamed on twitch while i'm making it everything on the youtube is cuts clips whatever from my twitch show so if you're not already watching make sure you go to twitch.tv theo where i'm live every wednesday around 2 or 3 p.m and i go live on fridays pretty often as well thank you again for watching this video really excited thank you
Info
Channel: Theo - t3․gg
Views: 252,729
Rating: undefined out of 5
Keywords: react, redux, reactjs, state, state management, jotai, zustand, mobx, web development, js, javascript, react query, data fetching, app development, apps, typescript, rtk query, rtk, redux toolkit
Id: 5-1LM2NySR0
Channel Id: undefined
Length: 36min 39sec (2199 seconds)
Published: Thu Aug 11 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.