Top 6 React Hook Mistakes Beginners Make

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the hardest part about learning react is not actually learning how to use react but instead learning how to write good clean react code in this video I'm going to be covering six mistakes that I see almost everyone making with the use State and use effect hook and it doesn't matter if you're a beginner or an advanced react developer chances are you're making at least one of these mistakes [Music] welcome back to web dev simplified my name is Kyle and my job is to simplify the web for you so you can start building your dream project Center and to get started we're going to jump into the three use State mistakes that I see people making the most and these are a little bit easier than use effect mistakes which is why we're covering them first the very first mistake that I want to talk about is using State when you don't actually need any state let's take a look at this example real quick we have state for our email and our password field which you can see we have on the right hand side of our screen when we submit our form we're just logging that information to the you know browser this could be like a fetch request it doesn't matter it just does something when we submit and then we have our form which has you know our input for our email and it has an input for our password and we have that value and that on change this is super basic code probably looks really familiar too and you're probably wondering what the heck is wrong with it well if you look at this you'll realize we actually don't use these State variables anywhere except for in this on submit and that means we don't care what the value of these State variables are as they change for example as I'm typing my email address I don't care what my email is until the point point that I hit the submit button right here that's the only time I care what this value is so I don't actually need a state variable to track that because I only need the value when I have this event listener being triggered right here so instead of tracking the state and causing a re-render every time I type a character instead I'm going to store these inside of a ref so I can say const email ref equals use ref just like that get rid of my state do the exact same thing for my password ref and now instead of doing this value on change I can just say ref equals email ref just like that copy this down for my password and turn this into a password ref now immediately when I say if we just get rid of this you state here and what we need to do is just comment out this long for our odd and submit there we go commented that out now you can see that typing everything in works just the same as before but when I click submit it's not actually going to log anything to my screen if I come over to my console you can see nothing's getting logged so in order to make this information logged out all you need to do is just say that we get our email ref.current.value and that's going to give me the current value for my email same thing for password I can get my password ref.current.value and now I have those values so when I click submit if I look at my console again you can see that is printing out that information and I didn't need to use any state at all for this so really the first tip for you state is think do I actually need this to be state that updates and re-renders my component every time it changes or can I use a ref because I don't actually care about this value re-rendering my component every time it changes and oftentimes especially with things like forms you can get away with using refs instead of having state now for this next example I actually have an entire component that's just a super basic counter opponent component so if I just come in here and I just remove all this and I just render out that counter component that we have and get rid of all this code we can just jump over into that counter component and we just make sure that this Imports you state there we go so now you can see that if I just change this to a plus we can hit the minus button change our countdown hit the plus button and it increases our count super straightforward component we're using state for this and you may look at this and think okay there's nothing at all wrong with this but the problem is is that we're updating our account variable by using the previous count variable and in order to do that in react you should always use the function version of the use State Setter so if you're unfamiliar with this use State Hook and the fact it even has a function version I'd recommend checking out my free react hoax course it's going to be linked in the description of this video but essentially when you set State you can either pass it a specific value for example I could pass it zero and it'll always change my state to zero when I click one of these buttons or I can use the previous value to try to set it to something based on that value so in our case what I could do here is I could pass it a function and this function will return to me my new value and this function will take in essentially my previous count or the current count this is what the count currently is so I can just say my current account plus my amount and now if I save this and click my buttons you can see that this is working exactly the same as it did before but why exactly would I do this when it still worked the same as it did before both ways work just fine let me comment this out and bring us back to what we had before and I'll show you why this is a bad idea so we can say count plus amount what happens if I wanted to set my account two different times for example like this this should increase my count by two every time I click the Plus or decrease it by two every time I click the minus so let's see if that works let's just do a refresh right click plus it only goes up by one same thing with minus it's only decreasing my count by one even though if I'm reading this code it says Okay add one to my account add one to my account so it should be doing this thing twice and it's only doing it once the reason for that is that this count variable is set every time you render your counter so when I render my counter the first time my account is set to zero so when I try to set my account all it is doing is zero plus one and then below that is doing the exact same thing my count variable is still that same count variable from the first time I set my account so it's still zero so it does zero plus one and again it returns to me one and the reason for this is that when you have multiple set States in a row what react does is it batches them all together and does all of them at the same time so my account variable never had a chance to change in between these two different functions while if I change this to the other version here this function version and I copy this down twice notice this is going to work like we expect when I click the plus and minus button you can see it's going up and down by two at a time and that's because when you call this function this variable that gets passed in is the actual value of our current count so in our case the first time it gets passed in as zero so we do zero plus one now the second one down here is going to be passing in one as my current count so I'm doing one plus one so my count goes from here zero to one and then from here it goes from one to two all the time I see developers of all different skill levels not using the function version of set State because they're like well I'm only modifying the count one time like you know in this case like I'm only modifying it once so why should I even bother with doing it or they just don't even know it exists and you should always make sure if you're using the previous value or the current value of your account or whatever state variable you're storing always use the function version because right now you may only be setting count once what happens in the future if you write some other code that sets the count and now you have two separate times that the count is being set and if you just copy pasted the old code it's no longer going to work because they're going to be clashing with each other that's why like I said every time you modify the state using the previous state variable always use the function version to make sure it works just fine and it's only a little bit of extra code so it's really not that hard now the final use State problem that I see developers run into is actually one that's more common in beginners not as much in more advanced react developers and that's the idea that when you update your state variable it actually doesn't change right away it doesn't change until the very next render so what you can see this is if I just come down here and I just say console.log count and if we just come over and we inspect our page go to my console tab what we can do is I've click the plus button here you can see it renders out zero I added one to my account so it should be changing this to one but whenever you call set count or set whatever state variable you have this happens asynchronously like I mentioned before that means that this count variable right here or your state variable does not get updated until the next render like I've already mentioned that means that you need to wait for these State variables to update and when they update it's going to re-render your component so anytime you want to get the value of something for example our count and do something every single time it changes instead of putting some code after your state Setter instead what you want to do is use a use effect and use effect allows you to pass in dependencies in our case I can say every time my account changes log out my account now if I have my code like this if I inspect my page you'll see by default it logs out zero and when I click the plus button you can now see it is logging out the value of one because it's waiting to see okay has this value changed has it changed has it changed as soon as this count variable changes it's going to run the code inside of it so if any point when you're coding you want to do something based on when your state variable changes instead of trying to do that in the same place you set your state like doing it here instead what you should do is you should move that into a use effect that runs whenever you actually update that variable speaking of this idea of adding use effects though it's perfect to move into our next set of mistakes which are all use effect related so let's just exit out of this counter we don't really care about this anymore I'm going to move into our app and what I'm going to do is I'm just going to add some State and a simple use effect so what we have right here is we have three different pieces of State we have a first name we have a last name and we have a full name and down here let's just do a simple form for handling those different values we'll just do three different inputs so we'll just say value is first name unchanged is going to be setting our first name so set first name e.target.value close that off we'll just copy that down for our last name as well and then we'll come down here and we'll just render out our full name so now if we just run this code you'll see that we need to import use State and once we do that we need to also make sure we import use effect and now you can see that we have two inputs one is for our first name and one is for our last name just like this and you can see when I change my first or my last name my full name is being updated so this is working like we would expect but it's not really optimal the problem that we have is that we're updating the state variable for our full name every single time that our first name our last name changes so we have a use effect for doing this but this use effect is really redundant because like I've mentioned in my use State example you don't really need state for certain things and in our case why do we need a state variable for our full name all that we're doing with this code right here is we're updating our first name which causes our application to do a full re-render so it re-renders everything and then it gets to this use effect and it says hey our first name changed okay let's set our full name so then that causes our entire application to do another full re-render so every time we change our name we're not writing our application once we're actually rendering it twice because of this use effect right here instead we should just remove this full name from state and instead just set it like this const full name is equal to and we can just copy this value right here we can get rid of this use effect right here and now when I change my first name and my last name you can see that it's only rendering my application once and this use effect is essentially completely redundant and the whole idea behind this first tip is you don't always need a use effect when values are changing to update other values sometimes it's fine just to update those values every time your component renders in a variable like this or sometimes it's fine just when those values change to do the thing at the time those values change for example let's say that I had a simple use effect this use effect was just doing a fetch request we just came in here and we're doing a fetch from some URL we'll just say you know whatever URL it is it doesn't really matter and then we're doing something with the data that we're getting for example we're setting a variable called Data with our data like that and then what happens if we want to do something with that data when we get it well you may think okay let's put that into a use effect so now we have our data and then we're going to console.log our data or do something with our data this would work just fine but again when we set our data we now have to wait for our entire application to re-render before it's going to log the data out and we're only ever caring about logging this data when we actually get the data we don't care about doing it every time our data changes we only care about doing it the very first time we fetch our data so this use effect right here is actually going to run every time our data changes which maybe we don't want so instead let's just move this console log up into here we can console log that D variable which is our data and now we don't need the shoes effect again we've made this use effect we redundant by moving the actual action directly to where we actually care about it happening so really the key here is if you're using a use effect hook in order to do these kinds of triggers where in reality you don't really need a use effect hook this is generally a bad practice is going to lead to slightly less performant apps and a little bit more confusing code to read it's not the end of the world but again it's not the best thing you can do this doesn't mean you should remove all your used effects though in our example here if we go back a little bit what happens if we actually wanted our data to do something every time it changed well in that case it would make sense to have a use effect for that because now every time our data changes whether it's the first time we fetch it or if it's like the seventh time we've updated this data this use effect is going to run so if you want it to run every time something happens use effect is the way to go otherwise try to remove them if you can because too many use effects is generally confusing to read and you don't always need so many now before we jump into the use effect mistake I see the most people making I want to talk about a pretty simple use effect mistake which is all about referential equality so I have a simple form component here that we're going to be using so I'm just going to import that form component just like that close that off and we can just get rid of all of the code that we have inside here we're just returning that form component and inside this form component it's really super straightforward we have three state variables our age name and dark mode and each of those are their own input down here and whenever we change our age name and variable you can see that they're updating just fine and our doc dark mode here is toggling just a dark mode background now the important thing about our use effect here is every single time we change our person which we defined as being our age and our name we want to log out our new person so we just do a quick inspect of our page and I just clear out my console you can see when I change my age we can see we're logging out the person with a new age variable when I change my name you can see that we're logging out the person with that new name variable but when I toggle my dark mode you also see it's logging out my person and this may not be exactly obvious why it's happening because you can see we're only caring about our person and our person only has our agent name and our agent name aren't changing when we toggle this dark mode checkbox so why exactly is our use effect hook here running the reason for this is because of something called referential equality if you're unfamiliar with that concept as a whole I have a video covering it I'll link in the cards and description for you but essentially what it means is that every time our component here renders it's going to re-render itself 100 so what happens when we change our age name or dark mode any variable at all it's going to re-render our component and it's going to start at the top and it's going to Define each variable and as you can see when we get to our person variable we're redefining this person variable with a new object so now we have a new object it may have the same properties but it's a brand new object and a key thing about JavaScript is two objects even if they have the exact same values are technically different from one another for example if we just go into my console I can demonstrate this exactly like what I'm talking about here you can see we have an empty object and I'm comparing to see if it's empty to or equal to Another Empty object and you can see this is set to false even though both these objects have the same values they are different objects which means they're never equal to each other for example I can say person a is equal to a name of Kyle and I can do the exact same thing but make this person B so person A and B have the exact same properties but person a is never going to be equal to person B and that's because they are technically different objects now if I define a person C which is just equal to person a now person a is equal to person C just like that you can see that that is returning true and that's because they're set to the exact same object they are the same object while person A and B we've defined them as two separate objects so when we run through our form component here every time we re-render our component we're creating a brand new person object and this brand new person object is not the same as our previous person object because no two objects are exactly the same they're always different values if they're different objects so that means when we check our use effect it's saying hey is this new person the same as our old person well of course it's not the same because they are different objects they are brand new objects so the way that you can get around this is by something called use memo use memo essentially will allow us to keep the previous object value around and only update it when certain properties change so here what I could do so I can just say use memo and I can return this value so let me just make sure but I'm returning this as my object and then for our use memo we care about any time the age or the name property changes just doing this right here is going to solve our problem let's just make sure we import our use memo just like that and now if we just do a quick inspect on our page go to my console you can see when my age changes or my name changes it renders but when we toggle dark mode it now no longer is updating that variable and that's because use memo is only returning to us a new object anytime our age and name changes now if you're unfamiliar with this use memo hook again it's covered in my free react hooks course it'll be linked down in the description for you really the big takeaway from this point is if you're using things like objects arrays or any other value that is compared using referential equality you need to make sure that you're not actually creating a new version of that object or array on every re-render otherwise your use effect is never going to do anything like you want it to now for this final example we're actually going to be covering just a simple custom hook here called use Fetch and the purpose of this is just like a normal fetch request as you can see we're taking in a URL we have a loading data and error property and every time our URL changes we're running a use effect which is going to fetch that url's data if it's successful it's going to set our data if there's an error it's going to set the error and then no matter what happens it's going to set our loading value to false and up here we should also set loading to True before we actually run this so by default it starts out loading and then every time our URL changes it re-changes us to loading of true and then we can change our data accordingly now just looking at this code you may think this looks like a normal use fetch hook this is exactly what I would write and for the most part this is going to work just fine what happens if our component gets unmounted or if our URL changes rapidly in succession well we're going to fire off a bunch of fetch requests in a row for example if our URL changes five times we're going to fire off five different fetch requests and all of those are going to take a different amount of time to get to the server and come back so if we fire off five different fetch requests we'll just say one two let's just do three for example and we fire them off a hundred milliseconds apart so this first one is going to fire at zero milliseconds this one at 100ms seconds and this one at 200 milliseconds and let's say that this first one it's going to take 150 milliseconds to arrive that means if we just add those two numbers together it's going to be done after 150 milliseconds the second one we're going to say is going to take 300 milliseconds to finish so at 400 milliseconds this one is going to return to us and this one here is going to take 100 milliseconds which means after 300 milliseconds it's going to return to us so if we just run these numbers real quick in order our very first result is going to come back first after 150 milliseconds it's going to update our data or error depending on what happens then our third request is going to come to us next so now our data and error are going to be updated for our third request and then finally our second request will finish so our data and error for that one are going to come through so in reality if we fire off all three of these fetch requests we're actually going to end up with the data from the second one and that's just because the second one took slightly longer to happen and this is a very common use case you know depending on network speed some of your fetch requests will take longer or slower for random reasons so if you fire them off close together it could mean that one of the previous fetch request actually comes back after one of the later ones and now your data is out of sync because now you have the wrong data you have the data from the second URL and not the third URL the best way to get around this is to make sure you always cancel your fetch request every single time your use effect changes and to do that you need to use the cleanup portion of your use effect so here we can return a cleanup function that's going to cancel our fetch request for us and the best way to do this is actually using the built-in cancel feature for fetch request so to cancel a fetch request you need to create an abort controller so we can just say controller is equal to new abort controller just like that and then inside of our fetch here we need to pass it a signal so inside the options we can pass a signal and the signal just comes from our controllers just called controller.signal so that right there is essentially hooking this controller up with our fetch request and then inside of our cleanup function we can just say controller.abort and what that's going to do is it's going to abort this fetch request immediately as soon as this is called which means all of the dot then dot catch and Dot final lead code are not going to run at all it's as if they did not exist and that means in our example where we have three different fetch requests and they came back at different times it doesn't matter how slow the previous fetch requests are because as soon as a new fetch request happens we're making sure we call this controller.abort which is aborting the fetch signal which means it'll never ever call our DOT then or dot catch and update our old data this is really important when you have this URL changing rapidly or if a component unmounts before the fetch data comes in well you'd have a bunch of memory problems because now it's trying to update information for a component that's unmounted but if you make sure you abort your controller you don't have to worry about any of those problems this right here is probably the number one thing you can do out of all the tips in this video it's only a couple lines of code and it's going to make every fetch request you you make so much more performant and it's going to work much better and there are the six biggest use State and use effect mistakes if you want to take your hook skills to the next level I highly recommend you check out my completely free react hook simplified course it covers every single react hook you need to know and it's going to be linked down in the description below with that said thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 398,126
Rating: undefined out of 5
Keywords: webdevsimplified, react hooks, react hook mistakes, react hook best practices, react use state, react useState, react use effect, react useEffect
Id: GGo3MVBFr1A
Channel Id: undefined
Length: 21min 18sec (1278 seconds)
Published: Tue Oct 11 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.