 Hello, hello, hello, hello, hello, hello. I'm just kind of getting some stuff set up here. I Am really really really excited to Let's see. Oh shoot. I'm gonna pop out this chat. Oh my gosh Okay, cool. Let's put this in Zen mode. Just getting a couple things last minute things set up and We'll start in just a minute Now I didn't really like advertise this Because I'm actually like I've been super super nervous about doing a live stream again Because it's been a minute. I think the last one of these did I did was in May and Every time I was like, you know what? I'm gonna do another one of those I talked myself out of it because it was it just super super nerve-wracking So I'm hoping to get myself back in the habit of doing these Because they're super fun for me and I get to learn I get to learn a lot. Um So I wanted to talk about what this whole thing is about today Probably spend about 45 minutes and the goal is to just work through some new material that I have on On react suspense and react cash now These are super experimental here. Actually, I'm gonna set up a different scene. Oh, look. Hey, hey It's my whole face now these are super experimental and I am trying to figure out how best to talk about them right now because I have a workshop in a couple weeks with egghead and That's gonna be fun. Um, but eventually this is gonna become a course So once all these things are stabilized I'm really hoping to make this a course that you can learn everything you need to know about how Suspense changes your applications changes your application structure all that kind of stuff so That's where today comes in. It's not fully fleshed out And that's why I didn't really like make a big deal about doing this this live stream, but You'll be able to see kind of like where it's at and If you if you have any feedback or criticisms, I'd love to hear that So, um, you know, maybe you don't see this live Maybe you see it later after it kind of gets like processed and put on my youtube channel. That's great Please let me know what you think if there was anything that was confusing to you Anything that I didn't do a good job explaining or if you have you've been explaining it to people and you have a better way I'd love to hear all that stuff So, uh, yeah, well, let's let's get into it. Is it isn't it's not quite noon Just in case anyone had like was was waiting. I'll probably wait a second So I'll talk about like what this I guess a couple things that you need to know so first of all, I guess if you wanted to Follow along you can get this code sandbox here. I'll paste that over here in chat so you can copy paste it It is code sandbox.io slash s slash suspense workshop dash ch like Chan X1D one-dimensional. I'm Want a one-dimensional Chan apparently and the way this thing is set up Let's see. Let's open this up. Put that back in full screen There are a couple like steps that I'd gone through and those culminated in these Lesson steps that I have right now, which I'll be kind of like ironing out as we go through this Now I have included in here a build of React cache now the reason that's important is because right now the build of in The build of react cache that's on npm doesn't work with the latest react So right now I'm on like react sixteen dot eight dot six I'm not sure exactly what the latest is. I've forked this from previous project, but The react cache doesn't work. It has some like additional expectations and you're gonna have to build a version of this on your own Oh, hey, Bill. Welcome Thanks for thanks for being here. I'm excited to have you. I'm glad that I'm not just doing this alone If you if you have any questions or things that don't seem very clear, please let me know So So react cash, I have a copy of it in here. It was built from react master Or I think I copied it from somebody else, but it's a version that works Now if you're going to play around with react cash, you can either, you know fork this project or You can Build react on your own. I know that might feel a little bit daunting and actually later today I want to make a video on egghead talking about how to build react from from master So if you're an eggshead subscriber, you can hopefully get that pretty soon So what are we gonna cover today? So I have the local cash. We're gonna use this index file I have pretty the pretty standard setup react react dom react scripts And then I added this one called sleep promise, and you'll see why that's important later It's really just for demonstration. You probably wouldn't need this in a normal project So here we go. What do we have in this index file? Well from the top we have just our regular imports all of the things that we're gonna be covering in this 45 minutes to an hour and Let's see We have one Fetch it's just kind of standalone. It's totally outside of our application and we have an application that just spits out some text actually I can kill this because we're not using any of those Styles and it just says a Pokemon go here So eventually the Pokemon are gonna get displayed there, but right now we're in two separate lands We have our fetch that's happening. We log that out We see all the Pokemon that we're getting from this endpoint. So it works but then How do we connect this data? To our application, that's the big question that we're trying to solve here today And there's plenty of ways to do that. There's plenty of libraries that would allow you to do that But today I want to show you how we start thinking about interacting with data with react suspense So first things first, I'm gonna close this shelf up right now because we won't need that Uh, let's see. So we're gonna go through this first section here now What we need to do is we need a bridge that's gonna communicate like when when when this data has actually been retrieved and Oh shoot. Oh my gosh. I did all that and I was still showing you my face Unbelievable unbelievable. I'm sorry Uh, so so one more time then this app is pretty simple It just has a headers on the top to import react react dumb and then oh my gosh a fetch which is just logging out our results here and An app that's rendering here and our goal is to marry these two using suspense Can't believe I did that Okay, cool. So the first thing that we want to do is we want to import Let's see. We're gonna import from react cash Now because react cash is experimental so experimental that we had to build it on our own from source It's going to we're gonna import unstable create root as Create oh, no, that's not my one unstable Create cash as create cash Now anytime I'm working with some type of unstable API like the unstable create cash API, I always like to alias it using this as Syntax in the for an import and one of the reasons that is is because Now I can use create cash anywhere that I would have used unstable create cash and when that actually becomes stable all I have to do is Delete that and I'm off to the races So that's a that's a nice little tip on how you can use modules Yeah, you're imagining the code. Yep. Yep. Sorry about that. This is the I'm like so bad at like actually like Transitions and live streaming so well, I gotta get better at that So let's see now. This isn't like I said, we're building this so I made my own react cash So that's the one that we're gonna use Okay, everything works now. Great. Hallelujah So What are the steps that we need to do now? Well, wow, I'm all over the place. Sorry. This is so We can't actually use these in production or I can't so this is I don't have like a lot of muscle memory Built up around this we're gonna create a resource not a cash So we're importing in unstable create resource as create resource from react cash Let's get into it So from there, we want to create a resource and we're gonna talk in just a couple minutes About what that what a resource is I'm gonna show you what that actually means But for now, we just want to hook these things up so first step is going to be function Pokemon and I call this a Pokemon collection resource Because it's going to have the collection of all of our Pokemons that we can use Pokemon Pokemon Pokemons and all the Pokemon that we can use and What that's going to look like is actually going to change this to let and we're going to use create resource and We're going to give it a function, you know, what it needs to do when we want to collect this resource and in that we're going to Wrap our fetch now. I'm not gonna grab that last part because that is Logging out the results, which we don't need to do In and with that we have created a Pokemon collection resource Nice and easy. So all we've done is we've wrapped this fetch this this this promise inside of a create resource and that is how we're going to be able to start connecting the pieces between the data and React so resource first thing you need to do Now resources have a function that we can call on them called read say hey I want to read data from this resource Now we can render that out like we would do anything else We would use these curly braces to interpolate JSX say Pokemon collection resource dot read and The shape of the data from this is in results. So I'm just going to call results right there We'll map over this and then for each Pokemon we will spit out a div and And that will have the Pokemon Name, okay, cool. Now our app doesn't work right now, but it gives us a helpful message So let's say app suspended while rendering. That's cool. That's a new new one. We haven't seen before But there was no fallback you I specified Okay, cool cool cool, and then it tells us how to fix that So we need to add a suspense component with a fallback Hire up in a tree to provide a loading indicator or placeholder display error messages on point love it So we can do that. So I'm going to use property access syntax here You could destructure the suspense component out out of our react import if you wanted to but I'm just going to Stay down here and use it like this App suspended while rendering. So it's still the same error And so we're going to put that other part that fallback here looting now We've done everything it asked, but it's still giving us this error so Why is that? Well, it turns out that just like error boundaries These resources and the suspense component actually need to be separated by a component Boundary so we can't just have like react suspense and then have it just Render the the data itself. We actually need to pull that out into a component So I'm just gonna cut that and I'm going to create a new component and see if this fixes our problem we'll call this Pokemon list and We'll define that up here function Pokemon list And We'll return a React Fragments oops cool So what's our problem now Now that error went away, but we're not rendering our Pokemon So something is wacky. Oh spelling Oops, oh my word Sometimes code sandbox is a little bit different than my regular VS code environment and that screws me up. Okay, cool So now the error goes away and we have everything that we need which is great So these Pokemon just to recap We were fetching them that always worked That's how where we started and in order to kind of hook them up to suspense We needed to wrap them up in a resource Okay, we'll go and we to do that. We just import create resource from React cache and we give it a function and say hey we want to read from from from this source So fetch this data from here And then from there we we wrapped our whole thing in suspense we provided a fallback and and Created a component boundary for our Pokemon list now once we when we had it in here directly That didn't work. We needed to have some type of like component so they'd be like separated in the tree I don't actually fully understand why that is but it is super important So yes, thank you. Thank you look as I appreciate it. I there's a little bit of a delay with the with the With a live stream. So thank you for getting that to me Let's see Okay, cool. So that's really that's that's that's what we got so far. So that is the whole first part of it and Now that we've got that everything is everything's kind of easy street from here on out But those are three pieces that you're always going to need you're going to need a Resource you're going to need to wrap that in a suspense component with a provided fallback And then there's going to need to be a component boundary The elbow those things in place you are good to go Now what I want to show you next is how this Interacts with errors at least I think that's what I want to show you next Yes, I'm actually going to skip this part. We can get back to it if we have a little bit more time But I'm gonna I'm gonna keep laser focused on the on the suspense stuff So what we're gonna do first is we're gonna break this endpoint and see what happens. So I'm just gonna add an X to the URL I think it's There we go. Yeah, that's what I need to do Okay, so we get this big bold browser error or I don't know We get this big bold error, right and it says a field fetch now We don't actually User wouldn't really see this because it's in like create react up and this kind of stuff gets pulled out in the production builds But we don't want it to just fail right for our users and for that. Um, we use an error boundary Now I am going to show you what I do every time I need to react error boundary I just Google react error boundaries that takes me to the react docs and they have this beautiful Copy pasteable Example right here for you. So if you don't have one already in your application, you can just copy and paste this one it's terrific and We're gonna do this We're just gonna copy and paste that code wholesale and this creates an error boundary component Now the only thing you need to know is is that there is this Component did catch if there is an error It has this log error to my service Function it calls that and since we don't have that defined, you know, if you had a service like, you know What was it sentry or bug snag? You could log it to those since we don't have one set up I'm just gonna console log this so that'll be our our error reporting service right now now what we need to do is Actually use our error boundary And I'm going to put that inside of our application now You might be tempted to put it in here. I do not recommend that I always recommend that you put all these things as high up as possible Don't try to abstract around your like react and and suspend stuff. I'll show you some Tricks for like how to do that later. But for now, I just want to put this as close to the top level of the app as possible So error boundary Right there Going to copy that. Whoops Okay, so now we've pulled that out We've surrounded that with an error boundary and we see something really cool happen now I'm just by adding that component now. We are catching that error So it's not getting all the way to the top where it's just exploding everything We've we've caught it and now we can do whatever we want with it Now we have this right here. That's a fine error message, but it might be nice to customize that So I'm going to Say like yeah, that's fine. We'll have that as the default but also If there is a this dot props dot fallback I'm just borrowing that because that's the language that the suspense uses and then we'll prioritize that So, oh my word Okay, so we're gonna say on here fall back and We'll say Couldn't catch them all Cool now this fallback can be just a string can be any like renderable thing or we could actually make this a component So that was like nice and big is like an H1 So we'll do that H1 Cool couldn't catch them all perfect. That's exactly what we want Okay, so we have we have our list that's gonna render if it doesn't While it's waiting, it's gonna show this loading stage and then if something breaks well, it's gonna say couldn't catch them all so let's fix our end point and So we fixed our end points and now we are fetching these these Pokemon. They're rendering delightfully Let's see. What did I want to do? Okay, so customize our error. We did all that stuff. That's great Okay, so we can see that everything's working the way that it's supposed to But it's hard for us to really see that that loading state. It does happen Keep prop stuff. I'm gonna hide that for now. It does happen You can see it briefly you might not even be able to see it on the stream because that's so fast So this is where that sleep function comes into play. I'm just for the Just for demonstration so you can see all this stuff coming together. I want to import this sleep function from Sleep promise and I'm going to just kind of artificially add a delay so Once we get our return, I'm gonna sleep for another 250 milliseconds Let's do 300. Okay. So you should be able to see now that there's a slightly longer delay that happens Loading shows up immediately And then once that promise resolves then all of the the other stuff comes in so cool cool cool So, where do we go from there? Well now we have an opportunity to Talk about what a resource does we have both the success state the loading state or all three of the success state the loading state and an error state and That is really what what a resource controls So in order to show you what that does, I'm actually going to make my own create resource So we're gonna comment this out for a little bit And let's see so we're gonna make a function because this is called as a function called create resource and and That is going to take a promise or we'll call this a venable something that you can call then on And what it does from there is pretty simple. It's going to return. Let's see. What are you gonna do return a? Object that has a read Function on it Okay, now what that read function is going to do is let's see. So yeah, so you can see we have a we're calling a resource We're calling that read function which returns the results Okay, so right now we have So we can throw an error and That's going to get us into our error state. That's one of the things that a resource does is that if something went wrong it's going to throw an error and then Boom. Now in order to see like this is that we're actually controlling this error. So like by default I think it throws a type error. Yep There's a type error by default and you can see that when I throw this error it is a you know Changing it to just error. So if I call this like a resource error, I don't know I think I might have to make a new error, but anyway, it defaults to reference error. I don't know anyway, we can That's one of the things that a resource does is that when the promise fails It's going to throw an error and that'll get caught by our error boundary Okay, so that's one of the first things it does. Um, now if it's in a loading state, it's going to throw that promise And that's how we know that it's loading. We know that it's the promise is unresolved And so it's going to throw that promise. They're like, hey, this thing isn't we don't actually have this data yet So just show the fallback state until we get it Okay, and then finally it's going to return once that promise resolves. We're going to return the result in this case it looks something like this with a Pokemon inside with the name of Bulbasaur Oh, that's not right. There we go Let's see result There we go. Okay So in in the case that when it's resolved, it actually is just going to return What it, you know, whatever the result of that promises So in our case it is an object with results with an array with Pokemon inside of it Now those are the three things that it does. So when you start it's going to Let's see. So when when suspense starts, it's going to throw this promise That's kind of like, you know, waiting to be resolved. You're just going to see your loading state And then it's going to either return all the results Which just returns the results and you know renders that out as you expect Or it's going to throw an error which you will catch and then display that error So those are the things that create resource controls Those are the outputs of create resource. Now inside there's actually a ton of magic That's going to happen around Watching those promises for their resolution and actually like connecting up to like scheduling events for the react Runtime all this stuff that you really don't need to think about anymore And that's the beauty of suspense is that you might have to think about it In resolving those promises yourself or using a library to do that for you And in this case suspense, you know, library is going to start depending a little bit more on suspense and kind of copying this create resource model to Do exactly that which gives us this really nice api where we just didn't you know have the pokemon list which You know reads from a resource And we just we don't have to hook up all of that like, you know, waiting Not sure when the data is going to come in You know, what do we show we just Give a fall back. It's awesome So anyway, I hope that you understand a little bit at a high level about what these resources are going to do So now that we've done that we can create a kill that We would jump back up Reimport that let's see. So yeah, we did all that cool. Perfect I probably shouldn't be deleting all of my notes, but just to save space So what do we do after that? Now You'll notice that no matter what We're always always always. Let's see. What time is it 12 22? Perfect. Oh, we're sailing along If you have questions, let me know because it looks like I might actually have time to To cover those questions So let's see. So we're sailing along How do we do this now? Uh, so concurrent mode Now you'll notice that Loading happens immediately Right away And the reason that is is because while we're using our suspense component We're not actually opting into the full concurrent mode that's kind of been been being tested in react So, uh, what do we do to to start opting into that? How do we get control of when that loading actually shows? We do that By importing something else from react dom now You've seen This for forever react dom render. That's the way we've been attaching react apps to the dom for As long as I've been writing react Now that has the potential to change And that will be with the introduction of Let's see create root Now this is also an unstable api. So create root As we're going to alias that Um and the api is slightly different. I'm going to comment this out because we will probably uh Use that again later. Um It's going to look like this create root And we're going to Use the root element And then we're going to render our app to it. So what used to be two arguments is now a function um, then You're going to call this function on your root. Um, and then you're going to call render on the return of that With the application that you want to render. So There we are. So let's uh render this again and see what happens. Okay. So this is interesting immediately just by changing that thing Now we don't see the loading at all Now I I want to make sure that you know that this is like intentional and not just like a blip or an accident So i'm going to change this to a whole second and you can see that when we sleep that for a second It still does nothing so How do we Now show our loading state now that this concurrent thing is kind of just waiting until the data is loaded Great question We have another api available on our suspense component called max duration And what max duration does is it allows us to specify How much time we're willing to wait before Showing the loading state Now why is this important? The the school of thought is that or research suggests that Somewhere around a hundred milliseconds people are able to or 300 milliseconds people start perceiving a delay Um, but before that they don't really they don't Really perceive it delay. Um, so when we just throw up a loading thing right away Um, that actually makes it feel longer because it feels because we immediately see oh, we're waiting for data and then you know We get the data so even if that happens really fast like if it happens in like a hundred milliseconds. Well it it It felt longer than if we didn't see anything at all So what max duration does is it allows us to communicate in our ui's Look If it's less than a hundred milliseconds like don't just don't even show the thing Don't show the loading state at all because like I'd rather just them not know that we're loading data and then just see data Um, but if it's longer than that then yeah, maybe we should show the loading state So i'm going to set this to zero which is the default for um, this this sync style the old style The current style of rendering react apps. Um, so max direction max duration Okay, so in order to get back to what we had with with this the default in sync mode is that Uh max duration is zero. We don't wait at all. Um, so let's start bumping that up So we're waiting for it's taking a second to get that whole request So if we don't want to see a loading state at all we set it to a second Um, if we were to say, you know what? It's appropriate for someone to have to wait 100 milliseconds before seeing a loader Then we can put 100 in there and we'll see that we don't see anything for a brief period of time Then we see loading for the duration of the time that it takes to resolve that request So that's where max duration comes in. That's where this new kind of like synchronous I don't even know i'm not even going to pretend that I know what i'm talking about here But that's where it hits you in practice Now I want to I think this isn't actually gonna work because Yeah, they're they're gonna resolve at the same time. Um If I had another request going, um, then I would be oops Actually, let's see Yeah, let's just let's just do another request Um, okay, so we it'll give us a chance to kind of cover everything that we learned So, uh, we have that we're going to actually collect a pokemon Uh, create resource, um as this we're going to take the id and Add that to the end Uh Cool let's also make that take a second sure why not. Um, so create resource we're gonna render a pokemon Cool cool cool cool Let's actually make that component So function pokemon Uh, this one we'll have to take props for because we'll need the id Uh, we're gonna return a react fragment Typing is atrocious as always um And then we're going to do that same thing. So we'll do pokemon Oh wait, I called this one pokemon pokemon resource, uh, we're going to Take our pokemon resource We're going to read from our cache take the uh, let's see I need to see what that data actually looks like pokemon of one Okay, cool. It is an object. Um, and then it also has a name. We'll just grab that name. I'll leave this open for now um, let's see Read Okay, let's see. Let's put this as a sibling at first This is going to be pokemon. Oh Ops id Okay, cool. We can see that at the bottom here. So I'm actually going to change this to an h1 And we can see that if I were to change this to two It would be ibasaur three venisaur Um, cool So we can see that those are are separate now. We're making two separate requests But we're rendering them in the same uh in the same suspense component. So, uh, let's uh, let's Let's tinker around with this and see what happens. So right now Both of those requests are in the same suspense component. So, uh, we have a max duration of 100 milliseconds before we show a loader And then both of those will display So what happens if we take this out side of our suspense component? Well, we're going to get an error and that's because we need to Uh, wrap that in a another Suspense component Let's see what happens now Okay, cool. So now we have we have two loaders. That's fine Um, and let's say that we want to change Let's say that we're willing to wait 100 milliseconds for this one Um, i'm actually going to put Yeah, 100 milliseconds for this one. Um, but we we know that this this one's maybe like a slightly slower end point So we're actually going to wait, uh 500 milliseconds for that one Let's do this come on Didn't work Okay, let's change this so loading Put this in a div too Just so we can see it on different lines Okay, okay, okay, okay Cool. So, uh, let's see. So we have max duration of that one And actually take these out so we can kind of start over So the whole thing is going to now we don't see any loading state It just kind of like waits until both of them are Both of them are ready and does its thing. So let's read. Let's wrap that in another react suspense um We'll call this loading your page It's gonna get more pokemon themed Gotta catch them all Okay, now we don't see that but we need and that's because we need to set a max duration Uh, so let's say right off the bat. I want to see that gotta catch them all What the fuck? Oh, sorry My bad my bad All right, so, uh Obviously, I didn't rehearse this part of it. So I'm kind of uh, kind of stumbling all over myself Okay, cool Let's separate one of these react that suspense I'm gonna start from the other side for a while since I've done this. I apologize 100 milliseconds All right. Well, it's obvious that I don't know how to I don't remember how to do this part yet Uh, what a bummer. I thought I had it. I thought I had it all under control I don't So let's uh, let's ditch that for now. It was I was I was so close. I was so close Am I spelling everything right? I thought that is exactly what I had done in previous iterations of this But it's possible that I am My memory is failing me Very possible. In fact, um, let's go back to uh, the code that we had before Which is uh, just spitting out this list Um, one of the things that I wanted to demonstrate in terms of the like Modularizing this code. Cool. So we did that one of the things I wanted to demonstrate in terms of modularizing, um, all of this code is How instead of wrapping this whole thing up into like, uh, you know, a big suspensy error-caught Component for rendering a list of pokemon. Um, how do I keep this separate while still abstracting certain things? And um, that is where I like to see Extracting around these components. So let's say we have this, um fallback Um, I'd like to see something like, uh, let's see pokemon collection Error Okay, and then we just define that function Error Cool. No, uh, we're not getting into that error state. So let's force it Couldn't get them all great. Okay. Um, so cool So we have now a an error component um And then let's uh, let's let's go into this one. So right here. We're going to be pokemon Pokemon list Fallback, we'll call it that Okay, and then we'll define that function pokemon list fallback Pace that in Okay, cool. So now, uh, all that stuff now we have this abstract abstracted out into components, but uh, we're not kind of like making some big massive component We're always going to compose these together. Um, so that we can have full control over, um, kind of our max durations As we need to modify those and tweak those um to have have this display the way that we want to to our Our consumers of our application So, uh, how I would modularize that let me just make a new file and we'll call this, uh, let's see pokemon Okay, and I'm going to Effectively pull out a bunch of stuff here. So we'll pull out the Resource, um, and I'll probably pull off that export collection resource Uh, let's see. We're going to need to import Uh, both of these actually Uh, let's see. So we'll import those. We're going to export this as collection resource and then from this side we will import uh collection resource as pokemon resource Cool that works now ultimately we don't even really need to if we if we don't want to we don't have to Export the resource at all. We could just export the components. Um, so let's take the list component. That's the Component that actually displays the list And let's pull that definition out and paste that here And actually, uh make the resource private So let's see. So this is going to call collection resource Um, because we're using react fragment we need to import react from react Perfect, and now what we'll do is we will pull pokemon list pokemon list I will change this to List as it's name spaced by the module Um, and that still works. So this is actually kind of like a fun way to um So we have this resource. Maybe we don't want everybody using this resource We just want them to consume the list component In which case we can keep this implementation private And then, you know, just just have it exposed through the component that reads it So that's pretty cool. Um Let's see we have these i'm actually just going to delete these so Since I couldn't get them to work But we also have our pokemon collection error and our pokemon, uh, let's see Pokemon list Fall back. So let's delete those. We're going to import them pokemon collection error and pokemon list fall back um I'm not exactly sure why it's still working There we go. That's more like it Uh, and then we'll export those from our module And see those kind of come back online And then again because these are namespaced I would probably change this to collection error and list fall back um Awesome, so that's how that works. And now we just kind of have our error boundary which i'm which I would absolutely Move into a you know more generic spot Typically you only need one of these per app, especially if it's customized in a way that you can provide an a custom error Um, so I would pull that out and really in this file You're really just going to have the app and the uh the the imports Which is really really really neat So, um, I think that's going to be it. We did 43 minutes. I do apologize for not being able to demonstrate the Uh, suspense much better and how you can separate children. Uh, that is my bad. I didn't really get to that. Um I didn't get to a place where I didn't get to a place where um, I had I had rehearsed that from the previous times that I had uh, I had gone through this So maybe that changed a little bit and my expectations were off. Um, but yeah, that's it. Uh, if you have any questions I'm happy to help Uh In uh, the eventual workshop that's going to happen, uh, next week on 16th with egghead Uh I will uh go further much further into kind of how this affects some of the other parts of building an application Um, kind of how we modularize things How this kind of interacts with context and hooks and all that kind of stuff Um, but for today, I just wanted to kind of reacquaint myself and uh, kind of like, you know, work with you on learning How to do this Suspense stuff just by itself. Um, so if you have any feedback for me, please let me know Uh, thank you for hanging out with me today. I really appreciate it. Um, and uh, yeah I'm gonna stick around for a couple minutes if you if you have any questions or uh, or feedback For me, um Let's see actually what I'm gonna do Pull some up real quick So I have, um, some I'm doing a I'm I'm doing the course If you want to join in for the course where we actually build this out it has styles. It has all that kind of stuff Um Let me give you some links. Sorry. I gotta pull it up on slack or uh real quick Let's see. Oh, looks like it's almost sold out. So, um, anyway, if you want to, um, I have a special link for For for just for you for for my friends here. Um, it'll get you, uh, 49 You can get in the the uh, workshop for 49 bucks Um, it's just for people who um, are you know, following me It's a way for me to be able to thank you for for kind of hanging in there with me, uh, and uh, yeah So it's usually I think it's 200 bucks. It's almost sold out I can get it for 49 bucks and we're gonna cover this And much much more, uh, I am really grateful for your time today Oh, thanks, bill. I I'd love the podcast the the podcast is like To joy of my life. I get to talk with like the coolest people and uh, just kind of hopefully deliver some like inspiration for For you to just realize that like all these people just kind of had an idea and started and um, they you know Things just kind of unfolded for them It's been super super fun. So I hope it's uh, inspirational at times to uh, to see just how easy it can be to To to put an idea scratch your own itch put an idea on the world and start Meeting cool people from it So, uh, that's it. Thanks so much for being here. You're great And I look forward to uh, seeing you seeing you maybe in the in the workshop I'll probably do this again next week because obviously I have a little bit of work to do um before I can teach it well So, uh, anyway, thanks for being here. I love you. You're great I just gotta find that find that thing. How do I how do I stop the stream? All right. Bye. See you