You Are Using useEffect Wrong

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
So many of you are using useEffect completely  wrong in your applications. So much so that   even on a useMemo tutorial video that I did a  while ago that has nothing to do with useEffect,   the most common comment that I get is, can I use  useEffect instead? No, you cannot. Stop trying   to use useEffect for everything. useEffect is not  supposed to be used for everything. It's supposed   to be used very rarely in a React application.  And so many of you are using it for every single   reason that you can find. And honestly, it's  leading to a lot of bugs in your applications.   So in this video, I hope to finally be able to  clear this up and teach you how to correctly   use useEffect and when to not use useEffect. Let's  talk about it. So let's actually take the useMemo   example, because it honestly baffles me that  people are seriously considering using useEffect   for this. So what we have here is we have a  component called the app component. And we have   one piece of state over here for the items. This  component also receives the filter through props   and the filters are defined here. It's basically  an object that has an optional search property   of type string. And then we have filtered items  over here, which is built using useMemo. And all   that this is doing is it's taken the items taken  the filters, calling the filter items function   with the items in the filters, and then just  returning the items that are currently filtered.   And then we're passing filters and items in the  dependency array of the useMemo. That's it. Now   this is perfectly fine. And this is actually the  correct way to do it. And if you're not familiar   with this, if you're not familiar with useMemo and  how it works, please go and check out the tutorial   video that I did on useMemo, because that is  going to explain everything accurately. However,   multiple developers have commented and  even insisted that this is incorrect,   and that actually, we should be using useEffect  instead, what they argue is that we should get   rid of filtered items here, and instead put it  as a state variable, and then use useEffect to   manually manage it, right. So let's do it. Let's  come here, let's remove filtered items, let's do   const filtered items, set filtered items, that is  going to be equal to useState. And we're going to   pass this an array. And then we're going to come  here and create a useEffect. So we're going to   do useEffect, import this from React, give it a  function over here. And then here, we're going to   do set filtered items. And we're going to do get  what is filter items. And then we're going to pass   items and then filters like so. And then we need  to provide a dependency array, which we're going   to do filters, and then items like so. And then  here we have a type error, which we can easily fix   because the types are not matching, we just have  to type our state here. So we can do string and   then an array of strings. And then we can close  this. And let's do the same thing for this one,   just to have it be consistent string, and then  close this. And now we have no more errors. So   this is what developers are recommending that  we do instead. Now, first of all, what I want   to say is that this actually works, right, this is  functionally equivalent to how we had it before,   we're going to have the same filtered items, and  they're going to be updated in the same way with   the same values as we had it before. But just  because this is functionally equivalent to how   we had it before, doesn't mean that it's better,  or even more importantly, that you should use it.   Because if you really think about it, how is  this component going to render, right, let's   take the initial render, right, this component  is going to be rendered for the first time,   it's going to have items here, which is going to  be an empty array. And then it's also going to   have filtered items, which is also going to be an  empty array, right. So that's what's going to end   up showing in the actual UI initially on the first  render. And then this use effect is going to run,   it's going to actually get the filtered items from  this function. And then it's going to set them in   the state, which is going to trigger a rerender of  this component and update. And only then on that   second render, are you actually going to see the  correct filtered items on the JSX on the screen,   right. So this is doing the same thing as we had  it before, but in two render passes. So initially,   on the first render, we're actually rendering  the component with stale data. Because let's   say for example, that we actually had a value  for the search initially on mount when this   component mounted search was something, we will  not show that search in the actual filtered items.   Because that only happens afterwards when this use  effect is run, which is only going to show up on   the second render of this component. So not only  are we actually doing two renders, which is worse   for performance, but we're actually rendering the  first time with incorrect data. And sometimes you   might actually see a flicker in the application,  which I'm sure that you've seen in your own   applications or in some other applications. This  is a common pitfall of react. And it happens when   you use this effect when you shouldn't do right if  you compare this to how we had it before with use   memo. So let's go back and let's undo all of these  things. Let's put them here. Now with use memo, we   actually don't need to manage anything ourselves,  we just declared filtered items, we just made it   equal to return filtered items based on the items  in the filters. And as long as we pass this in   the dependency array, this is always going to  be accurate given the filters and the items,   especially on the first render. If we have a  search here on the first render, that search   is going to be inside of this filters. And it's  going to be get taken into account here without   triggering a whole rerender of the components  that is more performant. And we don't even need   to worry about this at all. With this, we actually  never need to touch filtered items again, unless   we want to change the logic of how it's actually  computed. As long as we have items and filters,   and whenever they change, this is always going to  be kept up to date without triggering a rerender   of the component. So this is more performant. And  this is the correct way to do it not by using use   effect. And this is actually always what I try  to teach you in every single one of my videos,   I always try to teach you the correct way of doing  something. And I always try my best to explain to   you why we're doing it that way, as opposed to  doing it another way, right. So I hope that now   this is clear that in this case, you have to  use use memo and not use effect because it's   better for multiple reasons. Let's now look at  another example that I see very often in react   applications. And also a lot of developers think  that this is correct, this is actually worse than   the first example, that is a chain of use effects.  So over here, what we have is we have a card game,   we just don't have the actual UI for it. But you  can imagine that this would be a sort of a card   game, we have a state here for the cart, which  can have a property of is called if this card is   a gold card, it's a special card. And then we have  a bunch of use effects that basically are chained   together and react to manipulating that card piece  of state. So first, we have this use effect over   here, which listens to cart. So whenever we have  a cart, which can be no or actually have a card   value, whenever we have a cart, we're basically  checking if the card has gold. And if it has gold,   we're updating the gold card count state variable,  this one here, and setting it incrementing it by   one. Then once that happens, we have this use  effect over here, which is listening to gold card   count the state variable that we just updated. And  it's checking if this one is greater than three,   then it's updating the round setting the round  to round plus one, and then resetting the gold   card count simulating a new round, you have gold  card count zero, and you can start all over again,   then we have another use effect, which listens  to round and then if the round is over than five,   it's going to set is game over to true,  which then as a bonus, if that wasn't enough,   has another use effect that listens to is game  over. And that will alert the browser and say   good game and simulate the actual ending of  a game. This as you can hopefully realize,   please is a giant mess, right? There are a total  of four use effects over here, each listening to a   different part of the state, each triggering their  own updates and trying to sync everything together   to make something that is cohesively trying to be  a game. I mean, don't get me wrong, this works,   right? This is functionally functional, it  works. And you're going to have a game but it   doesn't necessarily mean they're going to have  a performing game that has the best code and   the best implementation execution of that specific  game, right? Like this is a nightmare to maintain,   trust me, I've seen a lot of projects that adopt  this pattern, this is so difficult to maintain,   because it's so hard to track all of these  different updates, right? You have basically   one update here that triggers this one, which  triggered this one and triggers this one, right?   This is a mess to maintain. And all not only that,  but also the performance implication, every time   that you set a cart, you're basically triggering  this effect, which is going to update one state   that's going to trigger a rerun of the component  that is then going to trigger this use effect,   which is going to set another update and trigger  another rerun of the component, which is then   going to set this use effect, and it's also going  to rerender the component. So every single time   that you set a card, you have multiple updates  in your component. And that is going to lead   to horrible performance. And what's even worse is  that just like in the first example of this video,   you actually don't need use effect to make all  of this work, you can actually do the exact same   thing without using any use effect. And actually  with using less state variables than what we have   now, let me show you. So what we're going to do  is we're going to come here below all of these   effects. And we're going to create a new function,  we're going to do function handle place next card,   like so this is going to take one argument,  the next card, so we're going to the next card,   and it's going to be of type cart like so this  function will essentially try to do all of these   things here in one function without having all of  these use effects. And without having to rerun the   component multiple times just to achieve the same  functionality. So the first thing that we're going   to want to do is pretty simple, we're just going  to do set cart and then next card like so right,   whenever we place a new card, we actually want  to set it in the state and have that update be   reflected because we're using it in the JSX  probably, which again is not written here.   But you can imagine that we will do that, then  instead of having this use effect over here,   which first checks if the card is not null,  because this card can be null. And then if the   card is gold, first of all, in this function  over here, next card is not going to be null.   So we can forget about checking for this because  we're only going to have this function be called   if we actually have a cart. So we don't need to  worry about that. But then we can directly just   take card that is gold. And then we can actually  render all of this here and actually increment the   gold card count. But what we can also do is we  can combine it with this use effect over here,   because this one checks if the gold card count is  greater than three. And then we'll also update the   round and then set and reset, sorry, the gold  card count. So we can put all of these together   in one place and get rid of both of these use  effects over here, which is great. So what we're   going to do is we're going to come here and we're  first going to do if next card dot is gold, right,   this is going to simulate this first use effect  over here, if card is gold, then we're just going   to copy this so that we have it handy, then we're  going to make a second check. And we're going to   do over here if gold card count is smaller or  equal to three. And the reason why we're doing   smaller or equal to three is because we want to  get rid of this use effect over here.And finally,   the only functionality that we need to have is  these two use effects over here. So if the round   is greater than five, we set isGameOver  to true. And then if isGameOver is true,   we actually alert a good game. But actually, do  we really need isGameOver? Because if the round is   greater than five, we can just directly alert the  browser with the same thing. So we can actually   get rid of isGameOver, right? We can get rid of  it. And then we can just take this code here,   if round five, and actually, I'm not going to  copy it, I'm just going to write it manually,   because there's a difference, we're going to do  if round is equal, equal, equal to five, because   here in this use effect, right, we're checking if  round is greater than five. The only reason we're   checking is greater than is because this is going  to run after it's going to run on the next render.   But here, and the next render being whenever the  cart is updated, but here, this update, this set   cart hasn't yet happened, because we're still in  the context of the previous render, right? So in   the previous render, we have to check round equals  equals five, instead of over than five, because we   are on the previous render. So if round equals  five, then what we're going to do is just alert,   and we're going to put it actually, I'm just going  to copy this code over here, because we do that,   and it's gonna be easy. We just alert good game.  And now we actually have the same functionality   as we had it before. But it's all in one function.  And more importantly, no use effect is being used,   and no component is getting updated, everything  is happening in one pass. And we don't need to   wait for updates to trigger different parts of  the code to run, we can put everything in one   single function, right? So we actually have  the update here, that's going to set a cart,   that's fine. Then we have this if check over here,  we're just going to check next card dot is gold,   that is this use effect over here, right? We're  not caring about null, because this cannot be   null. And then if card is gold, we're incrementing  here. And we're combining it with this use effect   over here, we're checking gold card count greater  than three, here, we're doing lesser or equal than   three, we're running this code. Otherwise, if it's  greater than three, we're putting this code. So we   can actually get rid of these use effects here,  because we don't need them. Then we're doing if   round equals equals five, which is this use effect  over here, but accounting for the fact that we're   in the previous renderer, we're not going to set  is game over to true, because we first of all   removed it from the state. But second of all,  we didn't need to have it in the first place,   we're just going to check if the round is five,  then we're going to do alert good game. And that's   it. So that means that we can get rid of this to  use effects here. And now look at our component,   it's much smaller, it's much more performant,  and it's doing exactly the same thing. And again,   this is a great example of refactoring code,  removing use effects, removing state variables we   had is game over before, which we currently don't  have to. So that's one less thing to manage. And   our application is much more performant, and it's  doing the exact same thing as we had it before. So   in conclusion, if you're thinking about using use  effect in your application, think again, because   chances are you probably don't need to. And  there's probably a different way, a better way to   achieve the same thing in a much more performant  way. That is a win across the entire board, right,   so I hope that with this, I was able to make it  clear enough that use effect is not the solution   for everything. And that oftentimes, there is  a better solution. And use effects should only   be used very rarely in an application when you  actually have to. And if you want to learn how   to correctly use use effect, and more importantly,  no one not to use it and want to actually use it   when it makes sense to use it. Check out project  react, which is my react course that is literally   going to teach you everything that you need to  know about use effect. And not only that, this   course will also teach you how to build a big and  complex application with react that looks exactly   like an application that you would see in the real  world. You will literally be guided step by step   on everything that you need to know to be able to  build a big application with react and learn all   the things that required to make that happen.  I've literally poured my heart and soul into   this course. And there's so much content in there.  And the students that are currently on the course   are loving it. And it's literally fundamentally  changed the way that they view react and the way   that they approach building projects with it. So  if you're interested and you want to learn more,   it's called project react and it will be the  first link in the description. And honestly,   if you've ever considered taking a react course,  this is the ultimate course, there is no other   course like it. And this is the one course that  are going to teach you everything that you could   possibly want to know about react. If you enjoyed  this video, and you want to see more videos just   like this one, make sure to leave this video a big  thumbs up. You can also click here to subscribe   or you can click here to watch a different video  of mine that YouTube seems to think that you're   really going to enjoy. And with that being said,  my name has been Darius Cosden. This is Cosden   Solutions. Thank you so much for watching, and  I will see you in the next video. Ciao, ciao.
Info
Channel: Cosden Solutions
Views: 32,604
Rating: undefined out of 5
Keywords: react tutorial, react crash course, react developer, learn react, react hook, react hooks, react hooks tutorial, programming tutorial, react hooks explained, computer science, tutorial for beginners, react component, learn programming, web development, frontend development, coding for beginners, simple code, easy programming, react, react native, useEffect, react useEffect, useEffect react hooks, useEffect cleanup function
Id: Jm9_Rk8K1NM
Channel Id: undefined
Length: 14min 39sec (879 seconds)
Published: Fri Apr 12 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.