 Sorry, this is a bad way to start. Hey, welcome. Thank you for coming here this morning. I'm glad you're here. Today, we're going to talk about Use Effect. Yesterday, we talked about Use State. This time, we're talking about the Use Effect hook. Now, this is kind of like a Swiss Army knife of hooks. It effectively replaces or gives us the ability to use a lot of features that we would have used in classes in function components. So yeah, so that's what we're going to be looking at today. I apologize. I'm a little kind of like frazzled because I couldn't get my screens to work. So yeah, so we'll kind of be figuring this out as we go along. So one thing that you need to do for sure if you're playing along is that something you need to know about Use Effect in the code sandbox is that this is like iframed in. So a lot of the kind of simpler effects that you will use and are documented, they'll kind of change the title or whatever. Unfortunately, those will not work in this traditional orientation of a code sandbox because this is iframed. So I can't actually communicate out. So what we have to do is there's this little button that allows you to pop this out. And once you've popped that out, you can pull that over here. You can use that like this. So that's kind of where we're at. Oh, you saw my terrible desktop for a second. I figure while we're here, I'll follow up on kind of what I did yesterday. Let's see. I'll follow up on what I did yesterday, which was after we talked about Use State, I kind of had this idea of maybe creating a custom hook that would allow me to basically use any load function or all of load ash effectively in a hook. And so I made that. It's real terrible. I'm not going to lie to you. It's a real terrible idea because I'm effectively reducing load ash, all of load ash, into a new object that I spread out literally every time that it runs. So this is a terrible idea. But I thought that it demonstrated something interesting, which is that you can abstract a lot of complexity away from people in using hooks. So at the end of the day, what I'm doing is I'm returning an object with the subject of my state and all of the updaters. So everything that's in load ash, you can do. And the effect that that has is that basically I take my subjects and I'm taking that as a list in this case, which I applied here. This is the default that I passed in. And then I can just use any of these load ash functions that I want, which is fun to play with. Again, terrible idea, fun to play with. So here on this button, on this on click, what I'm doing is I'm using the load ash concat function, which I did not define. I just mapped it over from load ash with a new array and then with a number four in it. So I can tap that that goes in. And then this button is the load ash function without two. So pretty easy. So if I hit that, two goes away. Anyway, again, I just wanted to follow up on some of the things that we, hey, Thomas, welcome. I just want to follow up on this is what I had played with after the stream. Again, this is really not a great idea, but this is a fun, fun code pen to play with because you can you can do this with any of the functions or I don't know, most of them, any of them that take like the subject first, you can then kind of pass in the all the other arguments and it'll do what it's supposed to do. So strings, collections, objects, it's really, really fun. And I think you'd like just change the way a little bit that you think about this use state hook. So now to start, I'm going to delete all of that because we're not talking about use state today. We are talking about use effect. So let's get this ready. I had thought that I got this ready, but apparently I didn't save it. It's all right. There's no way I can't don't think for me to hide this. So unfortunately, you can be stuck with this, but this is what we're going to be looking at over here. Now, and again, because of that iframe problem, the easiest examples are things like change the title, which I cannot do through the iframe. So use effect, we're going to pull that right off that named export from the react library. And then let's just see how this works. So an example that I typically like to start out with is a greeting component. It's like the simplest thing that you can make that takes a prop. So we're actually going to do that. Let's render out a greeting with a prop name. Okay, then we'll define that component and let's see that'll return. Let's do an h1 and do high props.name, take props, so that works there. Cool. Okay, talking and typing at the same time. Oh yeah, sorry. Thomas was just saying about the loadout stuff. Yeah, it's kind of a cluster, but it's so fun to play with. Like I'm not going to lie, it's super fun. I'm sure that there's a way that you could kind of make it quasi-performant instead of remapping load ash on literally every render, but it's fun to play with. There's a button, but I don't see it on your screen. Oh, yeah, let's see. For hiding it, I'm assuming. Oh, here. Oh, hey, thanks. Awesome. Thanks, Adam. Appreciate it. Let's see, let's go back into Zen mode so we can get some more real estate. Thanks, Adam, you're my hero. Perfect, this looks way better. Okay, cool, so we have a high chain task. Now, let's talk about use effect. So the first kind of example of use effect is this. So let's say we wanted to basically update the document title. Oh my gosh, can't type yet today. Okay, so we want to update the document title with this same text, right? Like so maybe this is like a welcome page or whatever. So we're going to use that. So let's say use effect. And the first thing that use effect takes is a function. Now I'm going to use this block syntax because we're going to, you'll see in a little bit, like we're going to need that block because we've got some things that we got to do. So here we're just going to do the work that we need to do. So let's say document.title equals, oh, that then selection doesn't work. So I guess we'll send it a template string. Like that, that should work. Does that not work? Let's say use effect. Document title equals, oh, okay, cool. So what you see now is that we have, oh, we have added that title here. So that's pretty cool. That was pretty, that was really, really simple. And we can kind of take this a little bit further. So we have our use effect call. If we want, we can extract this out. So let's see, oh, none of my VIM selections work. So let's say let text equal, we'll paste that in. We'll say text, like that. Okay, cool. So now we have, we're not duplicating that. So that's great. So this component is doing that. I mean, if I was, this should probably be greeting with title change. I don't know. We'll just be super verbose just in case. Or let's say title effect. Just because that might be, like, if someone was not really looking at the implementation and they just pulled a greeting component, they might not expect this to happen, this noun sense right here. So let's name it expressly. Okay, so this is cool. That was super easy. Everything worked. So let's dive in and see a little bit about what's actually happening here. Now, the truth about these use effects is that this is going to happen every time this component is re-rendered. And I wanna prove that to you now. So what we're gonna do is we're gonna define a function called, yes, Thomas, I love verbosity too. Way better. You can always be more generic in the future when you know more. So we're going to create a function called render. We're gonna wrap, let's see, not that. My bad. See, we're gonna wrap this, sorry. Yeah, and so everything disappears for a second and then we're gonna call render. Okay, cool. So all I've done is I've wrapped this in a function called render. And the reason is because I want to set interval and I want to re-render, I wanna re-render the app every second. Set interval is not defined. Did I spell that wrong? Can I not use set interval? Set interval. Maybe I have to call it from window. This is setting. Oh, oh my. Watching me struggle. Watching me struggle. This is what you show up for. Okay, why can I not use set interval? I'm gonna copy and paste it just to be sure. Sent interval. That was weird. That was weird. Why did that happen? Who knows? Okay, let's clear this out. Okay, so what I wanna do now is I just wanna test. So in my app I'm gonna log re-rendered. Just so we can see that in fact, it is re-rendering every second. Okay, perfect. That is great. I'm gonna move this down to the bottom and then I just want the console. That's all I care about. Okay, cool. So this is re-rendering every second, okay? And now if we wanna see if this effect is firing every second, we can do a log here. Interval, no T. Okay, so we can see that it's re-rendering and then refiring the hook. Actually, it looks like there's a little bit more happening, but you can trust that hook, this code is firing every time. Now we don't actually need that to happen. We don't need the document to update the title every time we do this. So there's a really cool little second argument here and it allows you to say what it is that you're interested in, like what the inputs are that you wanna track. So in this case, oh man, this happened to me the other day when I tried to demo this. Let me save this and reload. I did this wrong. I need to log that in the effect. Yeah, that's right. Okay, yeah, because the thing is this effect is gonna be called every time, but we just don't want to do the work if we don't need to do the work. So I apologize. I was logging in the wrong place because this is gonna get called every time, no matter what, or sorry, this is getting re-rendered. Out here it's just showing the component re-rendered again, which we knew to be true. So when I move it into use effect, we can see now that we render the document, the first render, the hook fires, and then it never happens again, right? Now, so, and that's because of the second argument. So right now we just have an empty array. So before it was undefined before, and that meant that it was gonna do every time. Sorry, that meant that it was going to fire every time. And the reason that is is because it's basically like, if you think about it from a class component perspective, it's like having a component did mount and a component did update. It's gonna fire for both of those. It's like putting in both places. Now, the way that you opt out is that you put this second argument. Now, that's only gonna fire one time. So it's effectively like the component did did mount, but without the component did update. So let's see, so let's see. So undefined or nothing is, I don't know. Let's say it's roughly like, oh my gosh, it's freaking me out. So it's losing like component did mount, empty array is gonna be, no, shoot, sorry. Component did mount and component did update, right? Entity array is roughly equivalent to component did mount only. And then as you add inputs in here, so if we track props.name, that's gonna be like as if you had, as if you had some like custom logic in like should update. So this is really cool because it's gonna do all that work for you. It's just gonna say like, oh, okay, like we are tracking this value now. If props.name changes, only then will we refire this work. So that's kind of where we're at. Sorry, I'm at the bottom of my chat here. Okay, so that's a little confusing because I think immediately it feels like undefined and empty array should be the same thing, but they're not as we've just illustrated here. So, no, I, when we did our interview, they said like to not really worry about this so much and only hang on, only worry about that second argument when you have a performance problem. So anyway, so I'm just kind of exploring the boundaries of this, but just know that that API is there and by default it's like undefined and you can add this array to kind of get that component did mount style stuff. But really what we want is we say, we care about props.name. So if that value changes, only then redo the work. And we should see the, oh my gosh, craziness. We should see the same thing happen as before. We'll see a render, we'll see hook fired and then re-render. Now if we change the name, it will do that. Unfortunately that's more code than I feel like writing, but you can explore that on your own time. Just kind of render it differently, randomly with different names. So yeah, so that's what we're at. So that's that first thing. So we got that second argument. That's kind of the big additional piece of use effect. Now let's try something else. Sorry, every time I do a save, but don't refresh hard over here, it's like all kinds of stuff. Okay, so let's do something different now. I'm going to take this out and I'm going to unmount this component. I can never remember the name of this API, but it's like reactdom.unmount component at node, I think. Yes, oh, first time, nice. Now you'll notice the component unmounted. Is that how you say it? I was able to unmount the component, okay? So the component mounted and then it was unmounted. But, and you can see this by the fact that there's nothing here anymore. However, this title's the same. The title didn't get cleared up. So that's a problem. Now, how we solve that with use effect is we can return a function to be called when the component gets unmounted. So we do that by just adding another line. And this is where that block comes in. So that's why we needed to do a block instead of just kind of, return it directly. Because it's kind of counterintuitive. There's a lot of counterintuitive things with use effect because the return value is the function that gets called on unmount. So you have to use a block in any case. At least that's my understanding. So if you don't use a block, that thing would just happen on unmount, which is super counterintuitive. These are things that you just kind of have to remember when using hooks because you're getting a lot for free, but it does kind of come at having to write code in a very specific way. So anyway. So what we need to do is on unmount, we need to change the, and I'm using the kind of classic, the class based words for this, the class based words for this. Just because that's the reference point that I have, I assume it's still the reference point that you have unless you're brand new to all of this. So I'm still using that language while I kind of map over the new concepts. So what we need to do is we need to return a function to the run, which is going to reset the title. Now, here, I think it was, I just called it react. It started as react. Now, it's kind of a bummer to like explicitly do it like that, but I just want to show you how it works for right now. So we're returning a function that's going to do that work of changing the title to react app again, and it does. Okay, cool. So, let's see. There are some improvements that we can make to this. I'd like to start by saying, I'd like to start by making this a custom hook. So, yeah, let's just start there. So how do we extract a custom hook? So we covered the first three parts, which is import used by basically just calling it. You pass in a function with a function block that does the work that you wanna do. If you want to do stuff when the component is removed from the component tree, you would return a function to do the cleanup work. And then there's a second argument after the function that allows you to control how often this thing is re-rendered. If you don't do anything, it's gonna render every time. Effectively, component did mount and component did update. If you pass in an empty array, it's gonna render only once or it's going to hook only once, I don't know. And then if we add the values that we care about, so what props.name is something we care about. If we use props.name, if that changes, then it will rerun only when we get a new prop for that. So very cool. Let's work on extracting these. These require a little, some additional work that use state didn't. So we'll just create a function for it. What do we call this? We'll call this use document title. Again, all hooks should kind of by practice use that, like use prefix. Use document title. We'll just wrap this whole thing. Okay, so we're gonna use document title. Now, a couple of things changed. So we don't have props.name because, well, this is just a function that's not living in a component anymore. So we have to pop that prop, pass that in. So we're actually gonna pass in the whole string because we wanna just, we're just concerned with updating the title, right? Like we don't want this nonsense in here, okay? So we'll say, how are we gonna change this to title? We're gonna track the title value. Cool, everything works again. Now, these are just functions. So now this isn't props, this is just, these are just function arguments which is awesome because now we can start to create our own API around hooks. So one thing that didn't feel right is this hook, no matter where it's used, it's gonna change the title back to React app. So I didn't actually think this through so I don't know how it's gonna work but what we could do is, let's see. I don't know how we would do this. Actually, I don't know how to do this. If you can think of a way in the chat, let me know because I'd be interested in, like basically grabbing the value before we mount this component and then my stomach's grumbling. Grabbing the value that we, like before we mount this component and then restoring it afterwards. So for starters, I could just do like, let's see, you could use context to grab the default title from parent context. Yeah, okay, well, let's start by just, so what I'll do is I will change the, so think I'm just gonna do the, we'll just call this like on or leave title. I don't know if that's a good thing. So at least we can just kind of, we can figure that other part out in isolation and then let's use like a default of empty string because I don't know if you saw that but like when it wasn't defined, the title went to undefined, which is not ideal. So yeah, so the title's undefined, that's it's not right. So we'll just do empty string because an empty string is better than undefined. Cool, so and the empty string is just gonna change it back to whatever the URL is. So that's actually great. So we're just giving it a default parameter of empty string. So that's awesome. Yeah, so how do we keep that? I guess maybe that's, let's see, so it's 9.30. Okay, I kind of wanna explore some other ideas. I'm sorry for introducing that concept. That'll probably be what I explore after this screencast because that is something that I would like to solve, I guess, is have this be something that allows me to basically insert it, know what a previous state of that was. And I do like that idea of context, that context idea was really good. Any way to use closure to save the initial document title and use it. Yeah, that's a good idea. So the idea is like to close over the document.title. Yeah, I don't know. I'm gonna leave that as an exercise for you and send me what you got because I'm super curious but also admittedly nervous about trying to do this right now. So anyway, send me what you got, I'd love to see it. So I did wanna cover a couple other cool things in use effect. I think the, oh, actually I'm gonna go right to that page because I don't know how to find it. So if we go to the hook stocks, I think they have a really cool effect that I just wanted to play with. Yeah, here it is. Okay, so they didn't actually, it doesn't look like they have it defined here. Use state, no. I'm sure that's going crazy on your screen. Okay, cool, we can just make it, let's explore. So what we'll do is, what is it, online, offline, and DN. So one of the, so this is kind of a funny story. So if you watch the keynotes, there was a joke made about the width of Mary Poppins. And so one of the problems, I think that they had like an online offline example, which is much more fitting in the Mary Poppins thing. Unfortunately, it's significantly harder to demo because there are two events. There's the online event and the offline event. And so they're like, is there a better, is there an API that's easier to demo even if it doesn't fit thematically with this being a Mary Poppins card? And so that's how the width came into be because it's a lot easier to handle the width than it is to do the two events, the online and offline event. And everyone was kind of being pissed off for a second about why there were two events for that. Anyway, just fun little facts, fun little tidbit for you. So in the spirit of that, I'm gonna come back to this and we're gonna do a resize handler first, just because that is what was demoed. So we'll start with that. So we have used document left with an assignment for you. Let's create a use window width. And I'm just gonna start this one as a custom hook. Obviously, I can do it in line, but I think this is something that I'll probably use a lot. So might as well start. Okay, so, sorry, I can't talk and type that much all at the same time. Okay, so what do we have here? So we have, okay, so what we wanna do, so this, we can't use use effect by itself. Now that's kind of like a bummer, but that we're kind of like going into use state because I wanna focus strictly on use effect, but a lot of times you're going to need to use use state in conjunction with use effect to hold the state and pass that along. So what we're gonna do is we'll start before we even use effect, we'll start with the state. So that's gonna be let width update width use state. State zero. And then we'll have to, as we learned yesterday, return something, probably just the width. That's really all we care about. So we're just gonna have an API where we just return the width, nothing else, because we don't want this consuming component to be able to update the width. So we're gonna use our width value. We'll get it through our custom hook. Let width equal use width. Use width is, oh, window width. Okay, so use window width. Use state is not defined, that's right. I love programming by errors. It's like I don't have to think that much. Okay, cool. So we're unmounting our component, so we need to take that out. Cool, so window width is zero. Now let's get it in honest to goodness, window width. Let's see, so it's, what is it? Window dot, document dot inner width. I spent so much time on MDN. I should really have this memorized at this point. Window, oh my gosh. I had it, and then I took it away. Okay, cool, whoo, that wasn't embarrassing at all. Just pretend like that didn't happen and keep watching. So, high chain statistic and then 59. Now, unfortunately this isn't going to adjust as we do this, so use state was great. It allowed us to put the initial window value in there and we have that value, but it's not updating. That's where use effect comes in. So we're going to set up a use effect and the first thing that we need to do is set up an event handler. Let's see, so the first thing we need to do is set up an event handler and we'll do document dot add events listener resize. And we need to handle resize. Okay, we don't have that defined yet. We're going to define it here, function handle resize. How that work going to work? It's going to take an event. I actually don't think we'll need it. What is it going to do? So it's resize. We're actually just going to update with, with the window dot inner width. That's one way to do it, I think. Let's see, so add, let's log it out first. Console log debugging. I could probably get it off of that event. I probably need to get it off of that event. Doing all this work and I guess, oh no, title effect. I was going to say maybe the name held up. So, okay, so what am I doing here? So handle resize is not getting called. Or at least not that I can tell. So, okay, so I'm going to go backwards. So I'm using width. I'm defining width here using my custom hook, use window width calling that, which takes me here. I'm using a use state hook and setting its initial value to window width, okay. So I'm getting the width and the width updater. I have a function which I'll come back to because it's not getting executed yet. So I've used effects. I'm giving it a function with a block. The work I want it to do is document.add event listener. I'm watching for resize events and I'm calling my function handle resize. Resize event handler. Let's see what we got here. What you got for me? Ooh, there's an optimized resize. Interesting, I'll have to read about that later. So let's see, resize throttler. Should be window not, oh my gosh. That's the second time I've done that. Thank you. Thank you, thank you, thank you. Here we go, document. Oh my gosh, this is a bad day for me with document and window problems. Thank you for the help. Does this work? Oh, hey look, log that a bunch of undefines. Actually, I don't think I need to update width, window.inner width. Okay, cool, that's working. Awesome, cool, cool, cool. Now, I don't want a memory leak here, so what we'll do is, oh nice. So I got the document.title closure set up working. Hold on, oh, I gotta show these in a chat, so. Show, show. Okay, cool, go, actually I'm gonna open those up. Nice. Okay, so let's move this, let's see. Okay, so it's not gonna update here. Let's get another window going. So we can see, see it. This is so cool, thank you for doing this. Okay, so we have our greeting. We have initial title is null. I'm just gonna read through it. And then we have our use effect. We give it our function with a block. Initial title equals initial title or document title. Document title equals props.title. Turn, nice. Awesome and not a static react app in place and it goes back to what it was. That is super, super cool. Thank you so much for doing that. That is awesome. I'm so excited that you did that. That's awesome. Cool, so let's get back to this resizer real quick. Oh wait, we got another one. Oh, we got a context version. Oh man, this is so fun. Oh, I have to uncomment and comment the last line. Oh, sorry, I'm gonna come back to it. Actually maybe not, kind of running on a long time. This is so fun, thanks for doing these. I love it. So there's a lot of like movement I have to do. Let's see. Oh my gosh. Okay, Adam's profile. Okay, so that's the top one, hide it in this view. Okay, let's just look through it. Okay, so what do we have? So we're rendering it. Okay, so we have a, oh, interesting. Okay, cool. So, gotcha, so we have a context provider that sets the default title to my app. Oh, interesting, so this could fall back, fall back to whatever the kind of next context is. That's really cool, I really like that idea. Okay, cool, cool, cool. So we've used profile and then that uses the use document title. And so then that gives it, that provides that string awesome. Okay, cool. So, if context has a title, we're going to pull that off of the context title. And then, so we render that. And then when we unmount or that component gets removed from the tree, we put the default title, which we got off of our app context. That is super cool, I like that a lot too. Dang, nice work, nice work. Awesome, awesome, I love it. Thanks for sharing, these are amazing. Yeah, these are super cool. Oh, sorry, toggle on unmount. Oh, sorry, I keep failing on demonstrating these examples. But if you're in there, you can click on them and put with them yourself. Let's get through, let's see. So we got this one set up. Let's make sure that we don't have a memory leak. Hopefully this comes back, we might be host. Changes to main are not saved. All right, well, we'll see where we're at. Oh, everything's coming back, everything's coming back. It's gonna be okay, stressful. Oh, oh yeah, okay, we got window width, we got window width. Give me back, let's see, is this all set up still? Yeah, okay, so we got that. Now, to avoid a memory leak, we need to when this, we need to give it return a function to be called when the component gets removed from the tree. So it'll be window.add event, let's remove event listing. Thanks for all the window help too. It's always amazing the things that I miss when I'm trying to type and talk at the same time. Okay, let's see, so we're gonna remove that. We shouldn't really see any effect of that, but it's gonna be good hygiene. You're gonna have a memory leak if you keep that event listener around for this particular component. And then, yeah, so I guess just as, like for the sake of argument, if we pass in this empty array, we'll see that this should never update it. So we'll get the initial value of 600, but then it should just stay at six, or sorry, 606, oh shoot, it's not. Crazy, so why is that? So that was my assumption, but apparently I was wrong. So use effect, if I say that I don't want to track any values, oh, gotcha, I'm responding to the resize every time. So I've already mounted the listener, so that's gonna keep calling handle resize, duh. So yeah, so in this scenario where I'm tracking state on my own that array doesn't really actually help me out in any way, yep, event listener's still active. Cool, well, good to know, good to know. Awesome, thanks for helping me explore the edges of this. Okay, cool, so okay, so we have a window listener, that's pretty cool. Before we call it quits today, do an off online one. So honestly, sometimes I just like to start from the very end to most point, the part that I need it, and then just kind of track those errors back. So, okay, let is online equal use online. Or I think I saw a better name for this somewhere, use network, okay. So use network status as undefined, let's define it. This is going to keep state, so I guess we can kind of use this as a model here. So let the status and update status will use state. And so what is that, how do we use that? So navigator.online, navigator.online, windows online. So let's turn return status. Okay, cool, so might need to, might just be a Boolean, actually hold on, I can just do that over here on the console. So what is navigator.online? Ooh, capital L, okay. That's a funny API. And then here, if I wanna see this, so I'm gonna have to do like, so isonline, because it's a Boolean, it's not gonna print things out. So offline, perfect. Online, offline, okay, awesome. So we got that. So we got the initial state. So just like we did with our window, we just kind of get that initial state and pass that through a state. Perfect. So the next thing we need to do is we need to use effect, we need to compose a use effect in there to continue to watch for those values. So online and offline events. I'm assuming it is, is it lowercase? I'm like super nervous. Oh, here it is. Okay, so I'm gonna copy both of these. Okay, I'm gonna wrap that in use effect, function with a block, return this guy. Let's see, update online status. There we got that, copy and paste that in. I'll just stick with that. Lazy. And then we'll call our state function. So update status with navigator.online. I'm sure that it probably sends us an event, but I think we can just check it. So now, I usually just turn my Wi-Fi off, but I'm tethered in today, so I'll have to see how I can do this. Network, offline. Date, state, oh, that's cool. So update state is not defined. I probably just typed it wrong. Use network, oh, make sure I'm doing this right. Update status on an unmounted component. Interesting. Okay, let's try this again. Okay, we're online. Oh, there we go, online, offline. Oh, I broke it by doing it that fast, I think. Oh, it's pissed right now. It is pissed. Okay, well, you can't go online and offline that fast, apparently. Come on, just load one last time for me. You can do it, you can do it. Okay, I don't know if that's gonna load for us, but we did get to prove that it all worked, so we have, I guess, just running through the code. Oh, Chrome. I pissed off Chrome, something fierce by tapping that like 30 times in a second. Let's see, we can see most of our code. So we have a new hook, a custom hook called use network, and it takes a really similar shape to use window width. It's totally possible that I, oh, yeah, it's pissed. I actually don't even know if y'all are still there. Oh, wait, we're back, we're back. Anyway, my things are not cooperating. So I thank you for tuning in. Continue to look at the code if you're interested in it. Play around with it. Thank you so much for the examples that you sent me. That was amazing. I am gonna play more with those document title ones. That was super fun. And yeah, sorry, there's a couple more chats that just came in, two events. Need to unsubscribe. Oh, yes, yes. Thank you, Thomas. If I could fix it, I would. But yeah, he was saying I have two events. So I'm, let's see, let's wait. Yeah, so I'm doing something really dumb here where I am adding an event listener and then on unmount adding the offline event listener. That was very, that was not smart of me. So yeah, so what I need to do is I need to add the online event listener and the offline event listener. And then I need to change this to remove event listener in both. So I need to add and remove both of them. Yeah, so anyway, yeah, so sorry that I did such a bad job there at the end. I was being lazy and trying to copy as much code as I could without actually thinking about what it did. So that's where I got into problems and that's probably why this is all jacked up right now. Anyway, yeah, my page is frozen. So I thank you for, thank you so much for watching. Let's see. Yeah, thank you so much for watching. I really do appreciate your time. I thank you for your collaboration, helping me navigate some of these things. Also for giving me those great demos. I really appreciate it. And yeah, I'm gonna be playing with these today. So if you have any ideas or things you wanna chat about, just hit me up on Twitter. Yeah, y'all are awesome. I'll see you tomorrow. I'm not sure what we'll cover tomorrow. Maybe use context. That seems like kind of like the next really big one. These are the work courses, but context is something that I use all the time. So I'm gonna play with that and hopefully I'll see you tomorrow. Thanks so much.