What React 19 Means for React Router

Brooks Leibbrand, Developer Relations Manager at Remix, discusses the evolution of React Router and the key features introduced in React 19. He traces React Router’s development from its early days Router to Remix’s v6, focusing on improvements in app performance and user experience.
Brooks highlights major updates in React 19, including enhanced hydration, support for custom elements, and better error handling. He also explains how React 19 improves compatibility with web components and uses modern web APIs for enhanced performance. Brooks emphasizes how these advancements lead to a more efficient and streamlined developer experience.
Share this talk
Transcript
I was gonna ask to come up to, Mr. November by The National, but Kent said I'm not allowed to. So you can all look that up later and then imagine me coming up to that song, and I'd appreciate it. Also, shout out Liquid IV. I've had a headache all day and it just is gone now. It's crazy.
Ryan was supposed to be on stage. He's sick, which is a bummer. So I'm here I'm here in your stead. My name is Brooks Leibbrand. I'm the Remix developer relations manager, and I figured to help, you know, fill in the gap. And the the sadness we have for Ryan.
I would try to make some accommodations throughout this talk. So hopefully everyone feels at ease now.
So like I said, I'm the developer relations manager, but really we're focusing on React Router right now, which if you didn't know is a product from Remix. And if you don't know about Remix, we actually are on a team from Shopify. So this should clear everything up. I don't know why people say we have an identity issue.
So what what does React router mean for? Rather what does React 19 mean for React router? As I was preparing for this talk, I realized I I really was asking myself this question first. I wasn't I didn't have the answers yet. I had a lot I needed to figure out and learn.
I've definitely, like, had a lot of ideas on the things I was interested about, but, like, specifically for our framework slash, library, router, React router. What does it mean? I had a lot of had a lot of research to do.
I figured it'd be good though to take a second and step back and just look at the history of React router and what have the various versions of React meant for React routers. So this history predates my career. We have the Ember router for React era. That was at the beginning. That was V1, V2, V3.
Ryan started that, Michael Jackson quickly joined. And they basically, React just didn't have a router. React has traditionally not really been this all encompassing all in one thing, so it needed a router. They took the Ember router and they liked how that works, so they made that version of it.
React context change, there was a minor thing that was one influence. Another influence was React's are promising component data loading. And so that really was the first shift to the v4 v5 declarative routing that React router did because, you know, the assumption was React's gonna handle this for us. So we don't need to do data loading anymore.
That lasted for a long time. Hooks were introduced. I didn't really change the API, just added more, maybe changed the paradigm a little bit more. But we got a lot more features in that. And then you get to like the, the remix stage slash v six. And it's really like this combination of v1 plus v4.
So anyway, basically, we we took in all the the routing into our our own, and we made a framework. And I'd say we haven't seen it on the team, but, you know, stolen data and all that stuff. And so we had this server side rendering remix, you know, data router. And it was pretty cool.
We added it to 6.4 so you had the lower level APIs as well. And now here we are at, React 19. We have RSCs coming, and so we have this new paradigm potentially coming, this this kind of new change.
So to address the elephant in the room, which is RSC, everyone's probably really wondering what I'm gonna say about it. And I'm really not gonna talk about it today. We have talked publicly a lot about what we're doing with React server components and how we're gonna incorporate them into React, into react router.
We have ongoing work about that. And I'm pretty sure you all probably saw Ryan's talk or a recording of Ryan's talk where he talked about that at react conf last year. In case you missed that, here's the whole talk. That's what our RFC plan is. Okay, y'all got it so we can move on.
So what does react 19 mean for react router? Well I wanted to go to the react 19 blog post. That's where I kind of started. I wanted to look at all the different APIs and everything they had. So I figured we would look at that together. And I'm just gonna read it out loud right now to everybody.
Nope. That's a terrible idea. That's where you laugh. We're not gonna do that. We're not gonna read a blog post, in front of everybody. So I'm gonna head myself. But this is this is definitely a very helpful like guide to to what we can kinda look at.
But if this is too many words, I need to simplify it. There are some really cool new, web browser APIs. I don't know if you guys have seen these. We're all about, you know, use the platform on the remix team. So we're gonna use some of these. We've got window dot, simplify react 19 blog post.
That's a good one. Okay, so that just removes everything. And then we got window dot remove the stuff that I'm not gonna talk about because I said I'm not gonna talk about react server components. And then we got window dot remove the honorable mentions. They're honorable. We won't mention them, just not right now.
And then finally as I was looking at this condensed list that somehow magically fits on the screen without me having to scroll. I realized that things I'm personally most excited about are all at the bottom. The things I care a little less about for reasons we'll get into are all at the top.
So we're also gonna call window dot flip it to the order that Brooks cares about. Great. Alright. We're ready. So we got all these things. There's a lot of things to talk about. Good news for you, a lot of these can be condensed into different groups. So we've got five different things we're gonna talk about.
Support for custom elements, hydration improvements, head management, the use hook, not a hook API. I'm gonna call it a hook every time. And then action but not server actions. And why not just throw the React compiler in there for fun? So let's talk about the React compiler. This actually isn't a React 19 specific thing.
This is also in beta. You can use it right now. But again, it's in it's beta so, you know, that's your own risk if you want to deploy that to production. But it's really cool and really easy. And you can use it right now in React Router applications. You don't need, my permission to to use it.
But if you do want my permission, you have it now. So what you do is you just take, by the way I have this little app. This is what we're gonna be working on. It's like a fake e commerce store. So we'll be gonna gonna see it a lot. You just take this little babble plug in.
This V plug in rather using babble. And you just go to your Vee config and you throw it in there. And you do have to import
this one. And now you can refresh and see an error briefly. Just that's just HMR. Let me get this in a position that we can gladly see it. And if you pull up your React, dev tools and if you zoom out a little bit, you can see that there's these like magic memo things that were added everywhere.
What What does that mean? It just means that everything got better. There's plenty of talks and blog posts and stuff, that explain what's going on here, but basically it's just it's memoising a lot of things. It's making things, just so much better.
We can see on our react 18, the old version, nothing specific to '18, just I don't have it in there. The same page. There's no special memos. There's one here, but that's like a custom one that was added. So that's just something you got for free. Free things are nice because they don't cost any money.
So we like that. Right. So that's the react compiler. Alright. Off to a good start. Now we got support for custom elements. Custom elements or web components, are pretty cool. Not something I'm honestly super comfortable with or really good with. So this example is pretty bad.
Don't like take and copy my code and actually use it because it's not good. But the idea of being able to use web components in React is really cool. For a long time in React, did not have good support especially when it came to server side rendering and the way that, props were passed down.
They were passed as attributes and not props and all sorts of stuff that I'm not gonna get too too into. But all that to say, custom elements are a lot more usable in React now that we have React 19, which is really great. So we're gonna demo that next.
And so I've got a little component, web component set up already called, I always forget what it's called. Color scheme. There we go. Colorschemepicker.JS. It's just in my public directory so it'll be easy to reference. And so inside of our root, we're going to update this color picker that we have here.
Let me make sure I'm on the right one. So So we can change the color from light to dark to system etcetera. So pretty cool. So we're gonna use a custom component for this. If we go down to the very bottom we can take a bunch of stuff and delete it.
And then what we're going to do is we're going to add, we're gonna look at what we actually called it. We called it color dash scheme dash picker menu. And there we go. And it can take a couple props. Well first let's get rid of this, because that's gonna be annoying all the time.
Say at TS expect error. Oh my gosh, error. I didn't figure this out. And so we can move on and say open equals, these are the processes we're gonna add, is open. So we have an interop between react and the the, web component.
And then we can have I always forget this one because I let Claude name it and it named it a dumpling. And so then we have scheme, the color scheme. So we're just passing those along. And then we have the on change event cause we do need to talk back to react.
Not like, not talk back to react, but you know, tell react what to do. So we're gonna take this. This should be all any. What are yeah, there we go. This one's kinda weird. Don't worry about this. I'm just gonna go through it. It's like e dot native event dot detail dot scheme. It's something dumb.
Anyway, so that's gonna do what it does and it's gonna work. So let's see if it works. No, it doesn't. Nothing pops up. And that's because we actually have to load the module itself when you're using, you know, this is this is JavaScript. I don't just have it directly in here. So this is like a web component.
You could think of it as, you know, being exported somewhere else or on some other place and we're kind of pulling it in. So the way that we can do this in React Router, we have this API, we have loaders and we also have client loaders.
So client loaders are really nice because they can execute something like a module, for us at the run time or at the load time once we get to a route. So that's what we're gonna use. We're gonna export the function client loader. Make it async.
And before I forget, because I always do this, we do want to add hydrate to be true because we want this to run on hydration basically. Which just means immediately. What's up? This is the arg checker. Yeah. It's good that I have a spell checker. I just was ignoring it. Alright.
So we need to pull out from route dot client loader args the server loader. Cool. So we just need to return this. This is a little bit fiddly but you know, it is what it is. And then we're going to call something called init module.
Sometimes it doesn't pick it up so let's just pull it in from React here. It's gonna be React dom though.
Init. Are you kidding me? Am I in the wrong one? Probably. Nope.
Oh my gosh. React. Okay.
Unit is it not called? It's what's up? Yeah. There's that one. No. Nothing's nothing's showing up. I'm gonna do this. Maybe. I don't know.
Let's try it one more time.
Preinit. There it is. I don't know. It was just silly cursor stuff. Alright. So preinit module. And so it's just, it's in my public directory, and it's just called color dash scheme dash picker dot js. And so we're gonna refresh this on the right hand side. And there it is. And we can click things.
Thanks. That y'all are just clapping because I was doing a bad job. But before, and it works. So that's cool. And then we can even, you know, click on the system and and toggle the system appearance and now it'll pick up the system that I have which is really great. So web components. Yay. They're good I think.
Hydration improvements. This one is is really nice. So the first one that we'll actually see this on is I'm gonna go to the the 18 version. And we this is actually an error that I see a lot when I'm on like the Remix website, the React router website in dev. It's really it's just a warning.
It's not actually an error. But basically, if you have a mismatch, if you have a hydration mismatch, you'll get this really, like obscure or obtuse, error that doesn't really make any sense. Warning rather it's not not really an error. But now in React eight nineteen, this error is so much better. It explains what a hydration error is.
It tells you what you can do, what you can, you know, sends you to a better link, and then it gives you a diff of saying like, oh, it's my HTML element that had a class name of, nothing and now it has a class name of dark.
And if we go up to my HTML, we can see like, oh, why is it doing that? Oh, it's got this color scheme, use color scheme, go in here and it's like, oh, there's a script that's running and that has to run before hydration. So we don't get a flash of white and there's reasons for it.
And so then we can just say like, well that's easy. I know what to do here. Just suppress the hydration warning. And if this bothers you, you can come talk to me. We'll go to couples therapy. We'll work through it. But this is really okay. So yeah. That's fixed and we can refresh and it is fixed. Cool.
Another thing that I couldn't really create a good, reproduction of but we have this problem with, third party scripts and Chrome extensions and things that can basically inject stuff into your head, that you didn't really have control of and you don't know that your user's gonna have. Like, you know Google Tag Manager is a good example.
And so we would get errors and discussion or, issues and discussions all the time about this. People are just saying like this is a problem, fix it, fix it, fix it. And we would say it's not a problem with us.
This is something React is planning on fixing and it's gonna come in the next version and finally it is in the next version for a long time. Jacob had, you know, this well he still has it.
Jacob Perez has this, article explaining the things you can do and like the best solution is to just upgrade to React 19. So it's nice when stuff is fixed for us. Alright, head management preloading link meta. This is my favorite one. Super excited about this one. So let's turn this back to a prettier code letter.
Not prettier, just more visible. So on our blog, and this is a very common thing with blogs is you you maybe have some very specific styling that's unique to a blog, right? Because you're gonna style your headers and all these things. You don't want that style throughout the application.
And so on our blog dash layout, we have a link. Like a very specific link to a a blog dot c s s, module. And so you can export a links function, from you know, for React Router to pick up and know what to do with that stuff. But now, we don't really have to do that anymore.
We can actually just put it in here. We can say link href equals, what did I call it? Blog CSS. And then we can what is it? Rel equals style sheet? Yeah. That seems right. And we can save that and it works. Let me comment it out just so you know that it it actually is doing something.
So that's good. Oh, it's because freaking, I got a dumb ESLint in here. Okay, whatever. No, it's a prettier thing. That's what it is. Okay, and so that just works exactly right. That link, is just something that react gives us for free. You couldn't do this in 18.
Declaring that it hoisted back up into the head which is really great. So we have one less API that react router has. Is this better? No. It's not necessarily better because there's there's kind of one little problem with this that's maybe not obvious immediately. This actually can give you a flash of unstyled content.
If you go to this page, if you client side navigate to it, you render everything and then it starts loading but maybe that module hasn't loaded yet. That CSS hasn't loaded yet so you get that flash and that's not really great. Whereas with the export, we already had that.
You can fix this by using, like a client loader like we did before and then do a preload with the CSS. I'm not gonna go through all that because we kinda already saw it. But that's not necessarily like, you're now just doing two things instead of one thing. So I don't know if it's necessarily better.
What I do like about it though is it's a bit more composable. So you can put this link inside of like a component, that you want to be able to share with other teams or maybe even share across like a next app and a remix app or whatever it may be or react router app.
And so it's helpful for that to have that encapsulation. So I really like that. That it's composable and it's more JSX and whatnot. But anyway, I don't know if it's better. But what is better is the meta tags. I really really like these. They make me really happy.
So I can just put a title in here and just, you know, call it whatever I want. We can see at the top the title says what I want it to. I don't have to like coordinate and put that in the head and everything. React is just doing that for me which is really nice.
So let's actually do a real example. We're going to do the loader data. We're going to hit the front matter. And if it exists we'll do something. If it doesn't we'll do null. We'll do a fragment here. And so now let's get the title like we were doing before. And we can get the loader data again.
And the front matter again. And this time we'll just get the title. So now we can see, also let me delete the one that we had before. So before it had to be a meta export. We had to do this kind of function and we're using the data and stuff but it's another function.
It's not really composed together. It's kind of a separate API. So we can just get rid of this. And now we can see that it does say markdown examples which is what I want, which is really great. Let's go ahead and for completeness sake do the meta name equals description.
And I think it's, it's always it's content, right? Yeah. I don't know why. I always think it's value. Loader data dot front matter dot description, there we go. Cool, alright so that's all good. What I really really like about this, not just that this is like more JSX like and composable and all that stuff.
Sure, we can say the word composable a million times until, you know, our ears bleed. But what actually is nice is a real example is if I want to like update a specific blog to have a unique title. So our React router tips there, central React router tips. I wanna make that even more exciting.
I want you to really want to read this when you see it in your your list of tabs. So I'm gonna go to the React router tips. Tips, MDX. And here I can just put a title. And I can like say like new and then I'll just copy and paste for now the title.
And now it says, well that's an HMR issue. Now it says new essential react router tips. So I can just right there in my MDX, I didn't have to do any coordination with extra data and whatnot. I can just like throw it in there. Because it's just declarative.
I can just tell it and react will hoist it up and whatever title was in last will be first. That's the heuristic they have and so that's really great. We like that. All right, use. I'm gonna take a sip. Hold on.
I'm no I'm no Dan Abramov. Please please hold your applause.
Alright. So the use API. We have these products. And on each of the products, when we go to the page or if we refresh it, we'll see that the reviews take a little bit longer to load in.
So that's a promise that we initialize on the server and then we send it down and then we we can render everything else but wait for it to finish loading before showing it, which is nice. That's suspense and a, I'll just show you. Details. Yeah, this one. It's suspense and there's a wait component.
So this wait component actually comes from React router. So instead of having to do this wait component, we can use a first class, thing. Let's and then we'll call it review well, resolved review. Actually, in honor of Ryan Florence, we're gonna do that. And so then we can just use, and then we can use the reviews.
So what that does is if there's a pending promise, it will, if there's a suspense boundary above it, it'll trigger that suspense boundary. And then once it's done resolving, it will just show me what I wanna see. This is mad because this needs to be a promise. So we'll make that a promise.
And then here we're gonna use it throughout. And then up above, we'll fix everything. We'll remove this line, this line, this line, this line, and then this just needs to be called reviews and we get rid of that. And now everything works exactly like it did before which is great.
So we've made no improvement but we changed the code which is how a refactor should work. And so, but there actually is one one nice little thing. So if for some reason we decided, hey, I don't want this suspense anymore. I just wanna see the reviews.
Then we can just get rid of the suspense boundary and react will automatically wait until all resolved like uses and whatnot and promises are resolved to actually render everything, which is really nice. And so then we can get really, fancy schmancy And we can go up here and say, is hydrant man.
It's so weird to write camel case. Use hydrated. And then so we can say, if is hydrated, that just means are we client side navigating? So we can do that.
And otherwise, if we're not client side navigating, like if maybe, you know, if it's the first time they land on this page or maybe like, like Google is like indexing it or something, then we'll show the full thing. Matt, can you fix the unstable middleware? It's still broken. Alright.
So I am refreshing and the reviews are just showing up immediately. But now I'm on the page, everything's loaded, and I go to a new page and the reviews are loading in like that. So it's nice that we have that little bit of composability with it. Yeah. Thank you. Okay. Last one. Actions.
This is my least favorite one. That's why it's at the bottom. So we're going to load up an example. I'm gonna add the load in parallel t shirt and also I'm gonna get the remix hoodie because they're both pretty cool. I wanna buy them.
So on this page, if I click remove, I'm I'm just making it to where they fell automatically after about two seconds. So I can trigger them and then, you know, as soon as each one fails, it's pinning state goes, you know, resolves immediately.
And I also wanna add this optimistic UI to where the total Well, like we know what the total is. So if I'm trying to remove the hoodie, it should subtract $59.99. So inside the cart, we can see how we're doing this. Okay cool. That's just that. We can see how we're doing this with like React router.
We're using fetchers. I still really like fetchers and it's probably how I'm gonna keep using things. But I I wanna see what React 19 has for me. So instead of using the fetcher, I'm gonna use action state. And here this hook takes two things. It takes a function as of the first or the second argument.
See I've done this like six times and I still don't know. Cool, it's the first argument. So it takes an action. We'll make it asynchronous because it will need to be. And then it takes a state or like a default state.
We're not gonna worry about the state in this one, but we will just declare it there because we have to. And then we're gonna pull out a form action and then you also get a pending state, which is nice because that's what we called that below. It's almost as if I knew I was gonna do that.
And then here, inside the use action state, this is where we actually wanna do whatever we're gonna do. Whatever like action we want to send. However we wanna talk to the server. Before I do that, I do need to make sure this form action is hooked up. So down here we get rid of the fetcher form.
We do a lowercase form. So that's kinda nice. That feels a little bit more, you know, like you're using like HTML or whatever. But we're still kinda cheating, because we pass in this action and then it knows how what to do with that action. And it's still like, you know, Rack is doing some special things with form.
It's all good. It's it's it's you know, it's kinda cool. I'm glad that we are using forms though. Forms are great. And so inside of here, what do we wanna do? We're gonna wanna submit something. Not submit an event. That would be silly.
And so I'm still gonna have to kinda use react here because or or react router because react router has like the way to talk to my loaders in a really nice way. So I'm gonna do let submit equals use submit. And then, yeah. And here I gotta pass some things.
So I need a method of post and, navigate will be false. And then I can't I I was having trouble getting to actually use the form, so I'm just gonna pass the data in here. So we'll say that the intent should be remove and then the, product ID should be item dot product ID. Cool.
And so now everything, I do have to wait this because that's what triggers the pending state is. It knows as long as it's waiting for promises to resolve. It should show the pending. And so now everything is the exact same as it was before. We're just using, a React component which is cool. Almost the exact same before.
There's one slight difference. I don't know how well Yeah. Y'all can probably see it pretty well. But these, these pending actions all get like queued up together. Whereas before if I hit remove and then a second later I hit this one, they would come back in the order like whenever each one resolves.
Whereas with like use action state, all pending actions are kinda globally queued up and all the pendings are like they're not like unique necessarily to their specific action. Not the biggest fan of that, but it is what it is. So we're gonna work with it. And there's other APIs you can use to get around this.
This is just actually wait, I don't know if that one's true. Anyway, whatever. We're gonna move on before I say dumb things. So what what do I wanna do last? The last thing we wanna do is we want to update that optimistic total. Right?
So the way we have to do this is we actually have to hoist everything up into the component above because the component above is the one that has control of this. So instead of me I I still want this use action state to be down here.
There's a couple ways you could do this, but this is the way I'm gonna do it. So instead of that I'm gonna pass an action in and the action is just gonna be a function that returns void.
So pretty simple and we already have written it so I'm gonna pull out all of this code and just replace it with my action. We're just hoisting it up. This is just normal normal prop drilling kind of stuff. So this submit will need to go back up into the cart. Yeah, there it goes.
And in here we can do the action and we're just gonna pass what we had And everything still works exactly like we had it. You know, just a true true hoisting refactor. So now we want that optimistic part. And this is this is kind of a nice little feature from, from React. So we got let.
We're gonna, it's kinda like a state. It's kinda like state and set state, but it's a little bit different. So we're gonna call it optin this is the worst word to spell. Total and then set optimistic total. And then instead of use state, we're gonna use something called use, you guessed it, optimistic.
So use optimistic is nice because it it kinda connects to the actions and knows how the actions are working. Whereas with the state, you would have to manage, all those those like pending actions and whatnot. So we're gonna pass into it the total. So by default, it'll be the total.
Whenever everything's resolved, it'll go it'll go back to the total. Excuse me. LiquidIV is, betraying me now. And then we pass into it, a reducer. And so the reducer is just gonna take a previous value and a next value. You can call it whatever you want. And we're just gonna add these two together. Very very simple.
For some reason, I have to give the type to this one. I don't know why. It doesn't just assume I'm gonna give it the same type. I'm sure there's a reason. I just don't know it. And so this optimistic total we're gonna use down here instead of the total.
And the way that we're going to update it is when we're calling our action. This is why I hoisted this up. Before we actually submit the action, I'm just gonna say, hey the optimistic total should be the negative of whatever item I'm on and whatever its price is.
So now we can remove these and we'll see that the price changes as we go, which is really nice. And then it fails and everything resolves back. So that's great. We could, you can clap if you want. You don't have to.
I like the React Router way better. Personally, biased definitely because I understand it better. I'm not gonna type it all out. It's just I I've done it. It's just it's way too much. And it's not interesting. So with React Router the main piece that you need to know is we have this use fetcher hook.
Use fetchers hook and this just has information of all the fetchers that are all happening at any time, anywhere. Which is great. And then you set these keys on them.
So I could say like, hey anytime you're doing the delete or whatever I want that to have a cart dash item dash and I'll give it a special ID.
So we can just loop through all of them, find all the pending removals, make that a little set and then go through all of our items and just say like hey what's in the set and what can we, what can we change out? And this just to me is more simple.
It's more like CSS one zero one just loops and everything. I like this. I can encapsulate it into, its own hook. So I just personally that's I like it a little bit more but you know it is what it is. Alright, so not in conclusion. Honorable mentions. I did say I was gonna get back to these.
We'll go through these very quick. So usually out effect. Before with server side rendering, if you were using a usually out effect, React would try to be helpful and tell you like, hey this isn't gonna do anything. And it's fine. It's like, yeah I know it's not gonna do anything.
I'm sending it to the client to do stuff. So they stopped warning us about that and said that they trust us now. So React trusts us enough to use that effect appropriately. So that's good. Better error reporting, just a great thing.
Not specific to React router, but hey, they deduplicated two errors that you would get and put everything into this one error. That's better. Cleanup functions on refs. This is a whole talk in of itself. Dominic has a great blog post on it, called avoiding use effect with callback refs.
So if you don't like use effects, maybe here's another tool in your arsenal that they gave you in React 19. Also use effects are fine. They're not bad. It's just the way we use them has been bad. But maybe that is why they're bad. I don't know.
Anyway, context as a provider, another thing that just gets simpler and nicer. And then ref has a prop. I mean, how long have we been waiting for this one? Thank you. Yeah. No more no more for ref. So just nice things not specific to react router but just nice things to honorably mention. So what does this mean?
What does react 19 mean for react out router? It means you can just do things. So what does React 19 mean for React router? I got to the end of this talk and I was trying to like have some great like idea or comment or like it enables all these things.
And honestly, to me it's just it gets back to what is what is special about react to me. What what why did I fall in love with react? Why did so many of us? Why does it keep continuing to pay dividends for many of us? And it's because it's all about composability.
It's not the only framework that does that anymore necessarily, but it still has that its heart. And everything they're trying to do with React server components and all these different APIs that they added, all the ones that I went through that have nothing to do with React server components make that composability better.
The use hook, the link, the meta, even just web components. You have a composability now with a with a web API which is really great. I think that's really good. I think it's sometimes it's nice when things just get better. We don't need the new paradigm necessarily always. Like we should push for those things.
We should try to, you know, expand our ideas and try different things. But also, if things just get better, that's nice. So thank you. If you like code, you can go ahead. But yeah, thank you so much.