Common React Mistakes: useEffect - Part 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Curious to know why isn’t he clearing setInterval on component unmount? By not clearing those timers, you end up with memory leaks. isMounted is a fancy solution I think.

πŸ‘οΈŽ︎ 8 πŸ‘€οΈŽ︎ u/geraldchecka πŸ“…οΈŽ︎ Apr 21 2021 πŸ—«︎ replies

Overall nice tutorial, thanks for sharing.

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/mutantdustbunny πŸ“…οΈŽ︎ Oct 14 2022 πŸ—«︎ replies
Captions
in last week's video we took a look at use effect use callback and use memo and some common gotchas around those but we didn't look at the cleanup function on use effect so in this video we're gonna do just that but before we begin if you like this video hit the like button if you really like the video hit the subscribe button and click on that bell and you'll be notified any time a new one of these videos comes out and also you should go into the interviewing channel on our discord server there you'll find a lot of great questions that will help you reinforce your react skills just like this video all right let's go jump into use effect and it's cleanup function so one of the things i do at my job is interview react engineers that means that i give them a test question and my favorite question is to have them implement a timer for me so we're going to actually look at that right now and see what a good solution would look like and see some of the mistakes that i've seen along the way so first off create a timer and the idea here is it's going to have a div that's got a number in it and that number just goes up by one every second it's not rocket science so let's first off create that count and then have a setter set count and just start off with a use date of uh say zero seconds that's fine and then we'll return a div that says timer and that count all right so now we need to bring in use state all right cool let's also go over here to our app and bring it in okay there you go timer is zero so this is actually this is the easy part of the interview now comes the more challenging part which is how do i actually make this run so the easiest way to do this usually make a timer in javascript is to use set interval set interval takes two different parameters the first is a function and then the second is the interval which in this case is a specified millisecond so a thousand milliseconds would be one second and so we want to do here is then go and set the count to the count plus one now this this code is not going to work in fact it's going to blow up in some amazing ways but it does kind of show that there's some misunderstandings here about what's actually happening so i think the issue is that people think that this div section down here is like a template that's dynamic that gets run uh on its own when this count changes so count we go and set up this interval and then down here this only this section of the function gets rerun every single time this count gets changed which is not the case right the whole function gets rerun so what's going to happen here is set count is going to get called and then the whole function is going to get rerun which is going to create a new timer so we're going to have tons and tons and tons and tons of timers so let's go and just go and show you that in the console say timer id equals zero and we'll just add one to it here and put that out in console log and we'll say that it starts with the count okay cool so let's save that and now my it actually looks in the beginning like it's actually going okay but when you show up in the console oh things are not going well here so we've got what three thousand four thousand five thousand timers all going right now and they're all starting with different values and it's crazy and it's a mess so let's get rid of that window and go back here so yeah that's what's happening every time we do a set count it's in turn creating new intervals which are in turn setting counts and all kinds of craziness is happening so what do we know from the last video well the last video we talked about how and when and where to set state and in the case of something that doesn't involve user interaction you want to use use effect if it's something involves user interaction you're going to want to use use callback but in this case we want to use use effect so let's go and bring in use effect and we will wrap this in a use effect and surely that should fix the problem right we just do that and we're going to leave the dependency array undefined so let's try that again we'll go to localhost 3000 and see what happens oh again looking pretty good on the outside let's see what it see what's happening on the inside okay similar kind of thing basically exactly the same thing uh because a re use effect without a dependency array gets run every single time the function evaluates so that's why it is essentially the same as doing it without the use effect so we need to add in a dependency array and we know from the previous video that if you only want something to run on load you use a an empty dependency array so let's just do that now we'll start and now we get another kind of interesting effect here so we went from zero to one and then we stuck there so what's happening now is the timer not running oh okay so we see that the timer is indeed running it's going every second it's firing off one of these messages and says cool we have one timer and it starts at zero every time so why is that well the reason that happens is because this use effect was called just once on load that's what you specified here on load and what was the value of count at that time well the value of count at that time was zero which means that this closure now has retained the value of count at zero and so it's always going to do zero plus one and give you one so that's not great so what you need to do well you need to use the version of the state setter that gives you the current value in a function and then allows you to return a new value so let's see let's call that current count and do current count plus one all right let's take a look and we'll refresh okay now we've got an actual timer and honestly for the purposes of my interview i would actually this is this is fine by me all right but we still have a lingering issue here of this particular warning so let's go take a look at that and we can see that it's telling us we have a missing dependency on count and that's because of this console log over here so if we want to get rid of that we could just go and put it inside of this we're going to return that and then for the console log we just put in the current count and now we're no longer getting that problem and in here let's see zero one there we go all right so that's actually starting to show what the actual current value of that timer is as well as what's on the display so you can kind of see it in both it's cool this is a good start but there is one problem with this and that's that we set an interval but we never actually get rid of an interval which is not really a problem on a very very you know simple page just kind of a short run time but if you've got like a single page application like a spa you really want to clean up after yourself clean up those resources so how do we basically show off that we have an issue with those resources well we have to create new versions new instances of timer in order to show that so i'm going to use a little trick i'm going to create a new state we'll call it index i'll start off with zero and i'm going to set the key on timer to that index now whenever index changes because of the nature of keys in react it will generate an entirely new timer so let's go put a button in a div here and we'll say update index and i'll bring in use callback and our callback is pretty simple it just sets the index to the index plus one and now in the dependency array what am i going to put in there well if i keep it empty like that then this callback is only ever going to get run the once on load and so this is always going to be zero so we really want to put index into here and now if you say oh whoa wait a second aren't you going to run into that cyclical problem that you do with use effect no the reason that you're not going to get that is because use effect actually gets run immediately when this changes whereas a used callback is just basically creating a new callback that will get run in response to some event right so it's not going to give you that cyclical uh nature so let's hit save and now if i update index here's some interesting things right so now timer one has stopped now there's a timer too but we are getting this interesting warning so it's saying that it can't perform a react state update on an unmounted component and this happened immediately when we clicked update index so we created a new timer and that old timer fired after it was gone so how do we trap against that how do we make sure that that doesn't happen how do we make sure that we only set count if this is mounted well what you can do is you can create a local value for example is mounted and we can start off with true because we know that this function is going to get called when the component is mounted and then you can return a function from this and that function can say we're not mounted because we know that if we get called if this cleanup function gets called we are not mounted anymore we're not on the dom so what do we do with this is mounted we can wrap that set count in that we can say we only want to call a set count if we are mounted and that's going to avoid that issue right so here we go timer one let's update the index and now timer two starts up cleanly and that's cool and this is actually a really good pattern if you have something like a fetch where you don't know if the server is going to get back to you in time before the component unmounts you can use this kind of trapping to make sure that you're always setting the state on a mounted component but in this case this is not actually the best way to solve this the best way to solve this is to use clear interval to get rid of this interval before creating the next one so what we need to do is just take the output of set interval which is basically just an integer but we'll call it timer and then we'll go over here we'll say clear interval and then we'll give it that timer and in that case actually you really don't need is mounted because when you clear the end roll it's not actually going to fire that again so you can get rid of that is mounted and the check and the initial state okay looking pretty good let me rebuild that and get a new component hey all right very nice and very clean now that interval is removed and everything's cleaned up and fine so that's that's great all right so i got a lot of great comments in the last video and one of them was around cleanup functions so i've already talked about cleanup functions right here with clear interval but another viewer said oh there's call max which is another great reason to do cleanups and i wanted to show that off as well and a good pattern for that so let me go and create a tooltip so i have a div here call it tool tip popper and when i roll over that i want to pop a tooltip so give ourselves some state tool tip shown set tooltip shown and we'll start that off at false and then if the tooltip is shown we'll pop this little tooltip timer down here so what we want to do is we want to add some on mouse over and on mouse out callbacks to that div now we could just use that using onmouseover and on mouse app but what fun is that we want to go and actually add those event listeners ourselves to kind of show off how to go and clean those event listeners up so we need to create a ref for that so i'm going to say that this is the tooltip popper ref and we got to bring in use ref and because this is typescript we need to tell what it is so it's an html div element but it starts off as null and now we want to make a use effect where we go and add our event listeners so we only want to do that once we only want to do that on load so we're going to use an empty array and again we're going to do a console log in here it's always good to put in console logs console.log is your best friend when it comes to usefx in particular to make sure that they're only running when you think you want them to run so we'll say that going to add event listeners so now we need some event listeners so i'm going to use use callback again i'm going to create on mouse over and on mouseout and on mouseover we want to set the tooltip shown to true and then on mouse out we want to set it to false easy peasy okay so now what do we do with these things well i'm going to go over here to tool tip popper ref and take the current value and then add an event listener to it and we'll say that that's uh let's say you start with mouse over and do on mouse over so interesting thing here vs code has automatically added the optional chaining operator for us and that basically says that if tool tip pop ref current is null then don't call at event listener only call at event listener if this is defined so that's cool thank you vs code for that and we'll do the same thing for mouse out all right so what's uh react complaining about what's complaining about that we don't have dependencies for on mouse out and on mouse over fair enough okay so let's go and add those in there's no no harm in that because basically these will never ever change so once that's created it's not going to get changed so yeah fine okay whatever okay so let's save that and i'll go and clear the console again and i'll update that index and now we can see that we're adding event listeners let's see if they work oh they do very cool nice we got a little you know kind of janky pop-up system there with the tooltips okay so now how do we get rid of them so we know that when we create a new one we're going to want to go remove those event listeners well so similar sort of thing exists but there is a little gotcha in here so let's uh let's work through it so okay um now we're going to go remove those event [Music] listeners and it's giving us an interesting error here so let's let's read through this so the ref value of tool tip upper ref current will likely have changed by the time this effect cleanup function runs okay why is that well here's here's the reasoning for that so think about how this this whole thing flows so the first time the timer gets run right we come down here we get our states we register these use effects but we haven't yet run them we come down here to create the ref we create some callbacks those do nothing again we register this use effect but we don't call it yet and then we come down here and we generate the dom elements so the no the react nodes for this which in turn go to the v dom and get turned into html elements which that is when that ref is assigned so at that point that ref is gonna be assigned and then this use effect is going to get called and that's why tooltip papa ref will probably be populated by the time that we get here cool but what also means is that when this ref changes maybe you move this to a different div or something like that based on some state or who knows what that could then change and so by the time that it comes down here by the time it runs this again this current will actually be the new dom element and not the dumb element that you're working with before and you want to remove the event event listeners on the dom element from before so you have to kind of cache that off so how do you do that well just basically go and get a ref so you can call it whatever you want but i'm going to cache the value of tooltip upper ref current and i'm just going to go and set that like so we'll add on there removing event listeners and let's go create ourselves a new component and we can see that we removed vent listeners on the original component and then as we created the new component we added new event listeners to that one so very clean and very safe so let's talk about a little bit about what we've learned in this one so we've learned about in primarily these these cleanup functions how to use timers how to trap is mounted for example if you use like a fetch you'd want to make sure that you used is mounted to make sure that if you got the result back after the component was unmounted they didn't set state on an unmounted component but in this case just clearing the interval is the fine and preferred way and then down here in our event listener use effect we want to first add it on to the current one and then we want to take a copy of that so that when we do the unload we remove it from that ref the previous ref and not the new potential ref all right there you go some easy fixes and gotchas around use effect hope you enjoyed it well i hope that gives you a lot more confidence when it comes to not just the how but also the why of how to use the cleanup function on a use effect if you have any questions or comments be sure to put those in the comments section down below but in the meantime from me to you be happy be healthy and be safe
Info
Channel: Jack Herrington
Views: 21,095
Rating: undefined out of 5
Keywords: react js, react js tutorial, react mistakes useEffect, common react mistakes, common mistakes in react, common mistakes in reactjs, react useeffect mistakes, mistakes to avoid reactjs, mistakes to avoid react hooks, react hook useeffect mistakes, reactjs mistakes to avoid, avoid mistakes for react hooks, react useeffect mistakes to avoid, avoid reactjs mistakes, avoid react hooks mistakes, mistakes in react hooks, mistakes in react, mistakes in useeffect hook
Id: F-0SZ_TicXA
Channel Id: undefined
Length: 20min 44sec (1244 seconds)
Published: Wed Apr 07 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.