Learn React Router v7 from the Maintainers
What has the team behind Remix and React Router been up to? DevRel and maintainer Brooks Lybrand teaches us about route config, type-safe routing, middleware, RSC/server functions, and more.
Resources & Links
Read the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone, and welcome to another episode of Learn With Jason. Today on the show, we are grabbing some of the maintainers of React Router and Remix to have a little conversation about what the heck is going on with Remix, React Router, with v7, and all of these interesting things happening in the React universe. If you're like me, it feels like a lot to keep up with, and I'm excited to have somebody on the inside to give us insight. So Brooks is joining us today. Brooks, how you doing?
BROOKS: Hey, doing well. Thanks for having me.
JASON: Yeah, I'm so excited you were able to join. For folks who maybe aren't familiar with you and your work, you want to give us a little background on who you are, what you do, all of that? Did I just kill the stream? Oh, my god. No, I didn't. It's fine. Woo. (Laughter) Oh, my ‑‑ yeah. Go ahead. Sorry.
BROOKS: You're good. It's great. My name is Brooks Lybrand. I'm a developer in Austin, Texas. I have been on the Remix team about a year and a half now doing DevRel for them, which means a bunch of different things, but mostly trying to focus on community, communication, and also like all our little special fun side projects like a store that's not been released but will be soon, our conference we're hosting in October, and all that good stuff.
JASON: Nice, nice. And so, how ‑‑ like, before you joined the team, how long have you been on the remix and react train?
BROOKS: Yeah, that's a good question. Let's see. I think I picked up react about 2017. I was a pretty ‑‑ I think I was still in college, technically. I was doing a lot of data science at the time, but we needed ‑‑ the company I was kind of part‑time working for needed more sophisticated UIs. So we started getting into D3 and data visualization and web technologies. That led me to web in general. Then it led me to realize, oh, I actually really like this a lot more than the data science stuff I'm doing. So I just kept on going down that route. Remix I learned about when it was still in beta. I was super interested in what they were doing, really following the work. Then I bought a license right before it went public, which is a great time to buy a license. At that time, I started doing a meet‑up in Austin with like four Remix ‑‑ that was, I think, 2021. So I was doing that for about a year, year and a half, which is definitely a big part of why I was able to get this job. It's just because I'd been building a little bit of that community already. I liked the way Remix thought and how it used web fundamentals, using the platform. Everything is built on the request response model. So I really liked that philosophy and was super hyped about it. I really liked this new thing they were doing with Remix. So I've been messing with it for about four years now.
JASON: Very cool, yeah. So I guess one of the things ‑‑ the questions that I have is it feels like we're at a particularly tumultuous time in the React in general. Like, it feels like we went from ‑‑ I don't know, I guess React has never really been a calm space. It's always felt like, you know, there's something going on in the compiler space. There's something going on in the ‑‑ I don't know, like we introduced hook, and that was a whole thing. Then there was like whether or not Redux is a good idea. So there's always something for us to worry about. But it feels like recently at least, I've been feeling tension that doesn't feel the same as the usual React tension around things like React server components. There's a lot of different nuanced things going on. I don't want to get into that today, all the things that aren't really the tech. But I am kind of feeling ‑‑ this feels different than the arguments over hooks or the arguments over whether or not Redux is the right call. Do you have any sense of why? Like, is there something that feels notably different to you? I have opinions, but I'm always curious what somebody who's much closer to it feels.
BROOKS: Yeah, for sure. It's a weird thing because I'm working on a team with, you know, our founders are ‑‑ they've been in the React ecosystem almost since it became a public thing. React Router is I think ten years old now, which is bonkers. Almost as old as me. No, just kidding. So, it is super goofy and it's hard because I definitely have their opinions that can influence me. I have just the outside perspective, which I try to still maintain. I definitely like ‑‑ I think there's organizational things that happen. I don't care to get super into that because it's not a blame game at all. It's not like, oh, Meta versus Vercel, whatever. There's people who know that story way better than I do, and I would be propagating in gossip at that point. But the biggest thing is React wants to be something a bit different. Honestly, we have a parallel story, and we'll get to that probably in a sect. But React wants to be in control of everything, in control of the server in a very different way. It had serverside rendering from the beginning. It's a pretty simple story. It's just generate markup and hydrate all that and re‑run it once you're on the client. We had that for, you know, since React has been around. That's been one of the core things. That's really what Remix is kind of built on top of, which is making that even easier. So that story makes a lot of sense. The RSC story is still relatively novel, and we've seen versions of it in different things like Astro. Its island architecture is a piece of what RSC is. It's like this version that's really baked into React and very inter‑op and has a lot of really cool features, but it is a completely different paradigm. So any time ‑‑ I mean, Next.js has done this, React has done it, and now we've done it. Any time you call your thing the same name you had before but introduce a big new paradigm, even if you didn't break anything, it breaks people's brains. So we just need to be a little more honest about that, I think. Instead of pretending like your brain is not broken.
JASON: I think the thing that's hard about this one is this is the first time it feels like the change that was introduced made things materially harder. You know, when you introduce something like serverside rendering, it's maybe a little more complex to set up, but it takes away a bunch of things that we were already doing that were really hard. When you introduce hooks, they are maybe ‑‑ you know, there's many pitfall, but compared to what we were doing before, it feels like a simplification and sort of like a convergence on something that had been like a known pain point in the community. The thing that's interesting about RSC is it's the first time that it feels like we were being told that something that we'd kind of already solved wasn't solved well enough and then told but we're not actually going to do it for you. You have to go find out user land implementations of this thing. The closest thing I can remember to having this feeling is when Flux was introduced, which was the precursor to Redux. We're not going to build it for you. We just think this is the right way to do it. Then there was this whole kind of controversy until we standardized around Redux. So the thing that's interesting about this one is that it sort of feels like we're being told the way we do things isn't good enough. We haven't actually built the way to do them better. We've just got this proof of concept, right. Then being told that this is the only way you should build, which then of course has the political problems of like, well, the one framework that had insider action to have that implemented before they announced it is now being kind of, by default, pushed as the right way because they're the only one who have implemented this pattern, which is where a lot of the tension came in. This sort of we don't actually have a solution that works for everybody. We have one solution, but we are going to say this is the right way to solve these problems. They've since done a bunch of back peddling and sort of said, no, no, it's not the only way, it's just a way. We're starting to see things like we're getting closer to an RSC solution in Vite. Remix has it, right? Or you're experimenting?
BROOKS: We have experiments. We might get into that today. It's not in a release currently.
JASON: Okay. Let's stop worrying about RSC because that's not what we're talking about today. I think it does set the stage then for sort of the tumultuous times that we're in. Remix has been ‑‑ a form Of Remix, has been at the center of React for the longest time I can remember because it's the same team that built React Router. We've seen this interesting thing where React Router has been at the center of the React ecosystem for a long time. It's one of the most widely used packages, if not the most used, in React. We've seen it split and remerge a few times. There was React Router and then Reach Router. That came back together and became React Router again. Then there was Remix. What if we did this other thing? And it's like just kidding, that's also React Router. So where do we currently stand on like what is React Router, what is Remix, where is the line between the two?
BROOKS: Yeah, that's a fantastic question. We're planning on making this story a lot more clear, like pretty soon. So I'll do my best to share what I can without spoiling stuff way too much. Basically, yeah, you're absolutely right about the history. That is the reality of it. It would be nice if we knew the end before we got there. I think our team is pretty good, actually, about forward thinking. We really do try to ‑‑ like, I know the yolk is that React Router is always breaking things, which is totally fair. I get that people have this experience, and that can be pretty tough. We really do try to be really forward thinking. We take a ‑‑ like, middleware is a recent example of an API. We haven't released for like four years. We kind of finally got to it. Very early on, it was what some people wanted, but we knew there were certain steps we had to do before we could get there. So we try to be forward thinking, but we also don't know everything we're going to do. For example, remix, when it started, it didn't use Vite. We had a custom esbuild bundler. The reason we didn't use Vite is because it didn't exist. So how do you know you're going to have a much better building block. So some of it's just difference of opinions of how we build this stuff. Yeah, Michael and Ryan had different ways they wanted to build things for a while. Then they came back together and wanted to build the same thing. They wanted to build Remix partly because it was their entire business was decimated by the pandemic. So they had to figure out what to do. They wanted to start selling software instead of what they were doing before, which was training React. So they took that approach. Basically, long story short, it is this kind of interweave back and forth. Remix has always been built on top of React Router. So as we've built up pieces and realize, oh, this could make its way back into the underlying routing library, that's a good thing for all the people using the routing library. So let's keep throwing it back into it. We really did get to this point where we had two things going on. We had a version of what we wanted Remix to look like in the future, mostly because of RSC. It really changed what we were thinking about, how we were thinking of building this thing. It really kind of made this paradigm, yeah ‑‑ just, there was this big paradigm shift. So we were trying to capture what do we want to do with that. As any project goes along, there are a lot of things you want to rebuild from scratch. It can be frustrating to go slow for everyone else. So we had that and this reality of it's like Remix and React Router are the same exact thing, except there's a Vite plug‑in doing some magic for you. It's taking your route modules and converting it into all the stuff. So at the time, I think this was like last March, we decided, you know what, we're going to take what Remix has been and put it back into React Router. Because this is a React story. This is what we've been doing with React for a while. This is our React framework. This is our routing in React. We're going to go that direction. With remix, that will hopefully clear us up to do something really different that we want to do. The only flaw in the problem, in my opinion, the flaw in the plan was that we took like a year to get to part two of that. So I think that just left this weird space where people were like why are you still calling yourself Remix if what you're working on is React Router. So that's the piece we're going to talk about a lot more soon. But I'm not at liberty to say, unfortunately.
JASON: Got it. Okay. So news on that front in the future. Watch this space. So in the interim here, what I think is really interesting is that, like you said, a lot of the things that made Remix powerful have made their way back into React Router. I think there are a lot of things that when I used Remix, when I kind of first looked into it, they were really interesting. There were things introduced in Remix that I think we've seen kind of make their way into other platforms that they didn't feel like I'd ever seen them before. They all now feel pretty common sense. So I think the thing that would be interesting is looking at, you know, what does it look like to use React Router today. Because I think react Router v7 versus v4 are very different things. For a lot of us, we're maybe maintaining older projects using older versions of React Router. So maybe seeing what it looks like if we start with a brand new project in React Router and maybe talking through a little bit of where are we seeing the influence of what was built in Remix showing up in React Router v7 as we go through and maybe build something out. I think that makes for a natural break point for us to switch into pair programming mode. How does that feel?
BROOKS: That sounds great, yeah.
JASON: Let me take a quick second and talk for a minute about our sponsors. We have a wonderful sponsor in G2I who has generously decided to support the live captioning on the show. So let me throw this nice little banner up for them. You can use G2i if you're hiring. Hiring right now is super hard. It's noisy. There are thousands of people looking for a job. It's rough out there right now. If you are in a position where you need to vet these engineers, you are getting flooded with résumés, you are getting ‑‑ it's a ton of time. It's making sure you get people with the right skills, making sure you're not getting fooled by people trying to game the résumé system or feeding you AI spam. So what G2i does is solve this problem by doing technical vetting for you with live technical interviews in a way that is sort of customized to what you need for your company. This means that you don't have to spend the time doing that. They've done this for companies like Shop Monkey, Detect. Go look at their site. They have a big logo wall. They can work with contract, full time, or contract to hire. They'll also help you hire like leadership roles if you need it. Honestly, if you're in a position where you are hiring right now, the nice thing about G2i is these are people you have seen in the community. There are G2i folks at conferences. They're hanging out at local meetups. They are the power behind React Miami, for example. This is a group that is actually engaged in the community and is actually plugged into what's going on in engineering. So these aren't kind of your typical template spam recruiters. These are folks who care a lot. So thank you very much to G2i for being part of this. And let me drop this link so that you can go check them out. I'll also just say if you are looking to get hired, there's a way to do that through G2i, too. So hit that up. Go check that out. And we will hopefully help you get hired or do some hiring. With that being said, let me pull Brooks back up on the screen. Let's talk about some React Router. Let me get my screen up here. There's the one. There's the G2i website. And we're going to pull up ‑‑ first and foremost, Brooks, what's the best people to find you if they want to learn more about who you are, what you do?
BROOKS: Oh, man. That's a great question. I don't have a personal site. Either just my GitHub or Twitter. It's just BrooksLybrand, all one word. That's everywhere to find me on the internet.
JASON: Okay. And there's links to Twitter there. We'll drop that as the core spot. All right. So go check out Brooks. And we're talking about React Router, which is this one here. So here are the links to React Router. So if I want to get started and I want to try out v7, what's our first step in is there anything you want to look at before we go, or are we just diving into the code?
BROOKS: No, let's look at docs. I don't know if you know this, but open source people work on docs. So people hopefully read them. It's really helpful to start there and not mess around with code and get mad at us if you don't understand things. We definitely ‑‑ these docs were not the best, honestly, when we launched v7. We definitely kind of fumbled that a little bit. But they're pretty good now. The first thing you'll see on that left‑hand side, you've got these different modes. If we started from scratch, I guarantee you we would not be doing it this way. Modes, that's a little confusing. But this is a historical ‑‑ you know, this is a thing that's existed for ten years. It has a bit of a history to it.
JASON: Yeah, you can break backward compatibility.
BROOKS: Yeah, it does a lot because routing is really central to any kind of application you want to build on the web. So declarative mode and data mode, we're not going to work with them, but we can talk about them. If you want to go to declarative mode/routing, that'll show you. This is the v4, I think. This is what I learned React Router as. So using components ‑‑
JASON: This looks like what I remember too.
BROOKS: Exactly, yeah. This is like the OG, like what if we did JSX for everything way of thinking about routing. This still works. This is great. It's very client side only. That's kind of the way you think about it. This is nice if you have a simple, just pure SPA kind of thing. Maybe you're using Vite to initialize a React project and you want really simple routing. This is still very great for that solution. Plenty of people are still using this. Then you have what's called data mode. So if you want to go to the routing section and data mode, it'll give you the best idea. This is a very config oriented version of building your routes. The reason that we have this version at all ‑‑ I mean, you can actually use JSX in this one, and it gets converted. This hoists all your data loading and actions and all these concepts that came from Remix up above, like at the top level of your routing. You can still use this purely SPA, but you're using your routes as your loaders and actions and all those sorts of things. That way you're avoiding waterfalls. You can do nested routing. You can do all the good stuff that you want that Remix has, but you're kind of building it up yourself, if that makes sense.
JASON: This is kind of like the React Router, the Remix way of solving the problem that something like TanStack Query was made for. So you have this component that needs to load some data. It's putting it all at the top and immediately starts loading and available where it needs to be available.
BROOKS: Yeah, pretty much. I will say TanStack Query is a bit more sophisticated. It's really nice if you have pretty complex stuff and you want those hooks for it. Pretty much like React Router, what it's doing is saying ‑‑ it's really an NVC model for React. We have loader, action, and component, essentially.
JASON: So we're saying in this route, you might need data. So just load your data here, and it will be available anywhere inside this route, which would be your view.
BROOKS: Exactly. The whole paradigm of loaders and actions, the way it worked in Remix, the way it works in this, everything should follow kind of how multipage apps work. If you submit a form, A, that's technically a navigation. It's not just an on click. That is a navigation. Then B, it's going to refresh everything. Now, we want to be a little smarter, a little better than that. We still want the SPA experience. So you are doing a client‑side navigation, but when you submit an action, it's going to automatically re‑validate all your loaders so your data will always be fresh. So it starts with a very simple paradigm. Then you can add all your caching layers to that as your application needs. But that's kind of the main paradigm.
JASON: Got it. Got it. Okay. All right. I'm with you. So this takes what we news as a JSX only thing, turns it into a config thing. We can kind of see how this all plugs together. What happens when we go up the stack here to framework mode?
BROOKS: Yeah, so framework mode, exactly. If you want to go to the routing on that one, this is going to look ‑‑ if you've ever played with Remix, this is going to look incredibly familiar. This basically is when we merged Remix into React Router. We did that last November. This is the result. Now you can use a Vite plug‑in, and it automatically gives you everything that Remix had. So your Vite plug‑in is going to look for things like route modules. It's going to look for your routes.ts file. It's going to find all these framework conventions and turn that into that lower‑level data router stuff you would need. That just makes it a lot more ‑‑
JASON: Oh, okay. So the way this is working under the hood, and this is I guess where you were saying that remix is effectively a Vite plug‑in, is that because we're exporting a loader from this component, then the Vite plug‑in can take that and change it into this kind of data declaration ‑‑ where was it? Did I go past it? Here. This sort of data declaration here. So from like a usability standpoint, this makes a little more sense, at least to me, because I'm co‑locating the request for data inside the view as opposed to up in the config declaration where I'm not looking at my view. Here's the thing that I'm returning, and here's where I use it, as opposed to having to go to my routes file to go see what data I'm loading so that I can then come in here and use it inside the component. Right?
BROOKS: Yeah, exactly. It really puts everything together.
JASON: In terms of what's actually being delivered, they're identical because the Vite plug‑in is sort of transpiling this over to that other thing. Is that right?
BROOKS: Yeah, pretty much. It's also doing ‑‑ like, you have other aspects. We'll talk about this, but you can do serverside rendering much simpler, just by turning on a bolding that says serverside rendering. There's a lot of hook up like that as well. So it's doing that initial render. It's doing the hydration piece. It's doing ‑‑ so it's exactly what you said, but there's so much coordination as well. If you were going to create a Remix or a framework with React Router data, you would have to build your own Vite or Webpack plug‑ins to handle all those pieces. At a high level, exactly what you said. At a detail level, it's so, so much that's being done for you.
JASON: Yeah, and this is like if you're not using Remix, this is why other frameworks are reaching for something like Vinchy. All those different decisions, none of it is mechanically hard in isolation, but when you start thinking about how all these different small decisions add up to be the developer experience of your framework, it's a lot. Getting it right is really, really hard. So that is something I remember. Seeing these types of patterns, I was like this feels right. This feels like the way I want it to do this kind of stuff.
BROOKS: Yeah, that's awesome. Yeah, and there's some other goodies that we've added with 7, but I definitely want to get into those as we get into the code. Just more things that having a framework and a Vite plug‑in does for you.
JASON: Great.
BROOKS: So if you're ready, I think we can jump into code, unless you have more questions.
JASON: No, I'm ready. Let's see what comes up as we go. So I'm going to ‑‑ let me just get a new thing going here. We'll zoom in a little bit. I could go back to the docs, but I'm going to ask you, what's the best way to start here if I've got an empty folder.
BROOKS: That's a good question. Typically, you can run an npx create router. But I'm going to ask you to go back to the docs. I'm just making you look like a fool. I'm sorry. Go to ‑‑ you can collapse that getting started section. Should be able to ‑‑ yeah, yeah, yeah. Then collapse like upgrading. Collapse API. We're going to try and find the tutorial. There's too many docs. There you go. Address book. Let's go to that thing. We're in the going to run through this. I have a video on this for people on their time, but scroll down just a bit.
JASON: This is the video here?
BROOKS: That's the video, yeah. If anyone wants to check it out, it's like ‑‑ yeah, you're good.
JASON: I'll drop a link there so anyone who wants to check it out can.
BROOKS: Perfect.
JASON: And you want the template. It's this one?
BROOKS: Yeah, exactly. It's going to have a little more setup, some data and stuff we can play with.
JASON: We're using the tutorials address book template inside the React Router repo?
BROOKS: Yep, exactly. Yeah, yeah, yeah. You got it. So yeah, our React Router CLI is just looking up GitHub basically. Or if you have a local template or whatever, it'll find that, but that's really all it's doing.
JASON: Okay. I'm just going to get all that set up. Then we're going to do all of our installs. This should only take a second. Then we'll pop this thing open. It's going to be React Router v7. There it is. Then let me open the right profile here.
BROOKS: For sure.
JASON: There we go. Maximize that. Okay.
BROOKS: That's so neat.
JASON: Super handy, especially if you go a lot of screen sharing and stuff.
BROOKS: Yeah, that's fantastic. I'm going to have to steal that one. All right.
JASON: Okay.
BROOKS: So, first thing, let's just run dev. That's always the most fun thing to do. We'll just run npm run dev and get this thing going. If you want to look at anything ahead of time, we definitely can. Here's our script.
JASON: Have you ever seen this? This is something so neat.
BROOKS: No.
JASON: If you hover, it'll run that thing for you.
BROOKS: Nice.
JASON: So we're going to go local host 5173.
BROOKS: Yeah, you got it. Perfect. Just the default. Not much going on yet, but it runs. So that's a positive first step. So that's good. So let's just start adding some data so that we can actually get this to work. If you'll go back to the code, and then if you'll go to ‑‑ there's a file called route.tsx.
JASON: There it is.
BROOKS: Cool. So route.tsx, if you've played with Remix, this is probably familiar. This is basically like ‑‑ it's the route. If you'll scroll down, I think there's a layout function or a component, rather. You'll see in there HTML. This truly is your entire application. Every single route is going to go through this thing. So this is going to ‑‑ yeah, it's going to matter a lot in a lot of places. So that's the very, very high level we have.
JASON: Nice. Brooks, I apologize, but I've been trying to hydrate like hell, and that also means I now have a fairly urgent restroom need. I'm going to ask you a question from the chat, and then I'm going to sprint. So I'm going to phrase this differently. What is the different use case for React Router versus TanStack Router? I'll see you in a second.
BROOKS: Go for it, okay. So yeah, TanStack versus React Router. If you think about it as the client side library ‑‑ sorry, client‑side routing library ‑‑ that's the more similar comparison you can make between them. If you compare those two, what TanStack Router has is a lot of typesafe features. That's what people really, really love it for. So at that level, it is very typesafe. Like completely typesafe. So it's nice at that level. If you're talking about a framework, you have to bring it up into like React Router framework mode versus TanStack Start, which is the TanStack universe, their version of what a framework is. So if you're looking at TanStack Start, there are a lot of similarities, honestly. There's a lot of similarities in how they work. There's some differences. The main thing to note is just, first of all, it is ‑‑ there's not a v1 yet. It's still a beta software. So try it. You absolutely should try it. The biggest difference is the fact that Remix and React Router 7 framework mode has existed for about four or five years. So it has been in production. Multiple big companies have built on it. That's honestly the main meaningful difference. As far as the technology differences, Tanner is going to be a way better person to talk about those things. The biggest thing is it build on React Query and all these different features. If you're talking about TanStack Router versus React Router like a data mode, they have a nice version of that. I don't know a ton about TanStack router.. I don't really use it day to day because I don't have complaints with React Router to where I feel like I'm trying to search for another route solution. Hopefully that answered it, but there's a bit of nuance to that question.
JASON: For anyone who's curious, Tanner and I are trying to coordinate on a show. We'll try to do a similar walk through. If you want to see the difference, hope any you'll be able to watch two parallel episodes where we kind of walk through both. Okay. So thank you for the brief break there. Why don't we keep rolling. You said in the layout, the layout is the root. We have our HTML, our body. This is exactly what I would write in my index.html, which I notice neatly I don't have to have here. That was always like a little jump in React that I didn't love. You sort of had just this tiny bit of why your React code that was an HTML file that was separate and different. I like that it all feels like it's all part of one thing now.
BROOKS: The disgusting metaphor we like to use is it has its guts out. You can see everything. We're not hiding anything from you. Cool. If you'll scroll back to the top, the root has the layout. That's kind of unique. We're not really going to talk about that here. We have docs on why we have that layout. This export default, this is very typical of like every single route will have a default component. This is what's going to get rendered. So inside of that, there's a list. It's just hard coded data. We're going to add some data here to make this work. Cool. So above that ‑‑ yeah, go ahead.
JASON: Just doing a little bit of compression here so we can see.
BROOKS: No, I love it. So above that, let's export a function. We can make it an async function for now. And we're going to call it client loader. We'll kind of get back to why in a second.
JASON: Okay. What is this?
BROOKS: Yeah, you got it. All right. That's perfect. Then here, let's go ahead and ‑‑ sorry, I got to pull up the actual docs myself to remember. All right. React Router. So from here, we can return whatever we want, but we want to actually pull in some data. There should be a file called ‑‑ yeah. I think it's just called data.
JASON: Data.ts. Here we go.
BROOKS: Let's find the first export we have in here.
JASON: We have an export. So we want this one?
BROOKS: Yes. Let's import that. This is a fake database. Here you would be using maybe an ORN that's connecting to a database or whatever you're using. Or even connecting to GraphQL or Rest endpoint or whatever.
JASON: And do we want it like this? Did you want to do anything to it?
BROOKS: That seems fine, yeah. Let's return it. It's going to return an array of these contact items. So how do we actually use that? What this means basically is when we actually run just any route, but the root especially, it's going to run the client loader. You might have guessed it's going to run that on the client. We're not doing anything server oriented yet. We actually want to use this data somewhere. So we don't have RSCs. We're not doing that await async in there. We're going to pull it down in here. You're already guessing we're going to use something called use loader data or something. So that would work. That's great. Let's try that. It should come from React Router. Let's try and map over ‑‑ yeah, it doesn't have a type. That's kind of lame, actually. This is lame. We need to give this types. So we could pass a generic in here. We could do all this stuff. Instead, let's actually open up on line 19, we can get some props from, like, for our component. Kind of injected into it. Yeah. It's just going to be called loader data.
JASON: Oh, we just get one called loader data.
BROOKS: Yeah, you got it. Then how do we get the types on this? So, let's go ahead and annotate this on the right‑hand side of that curly brace. We're going to ‑‑ let's not type it out. We have something way better.
JASON: That's what I wanted to hear.
BROOKS: All right. Just capital "R" route. We already have it imported on line 8, which is why it exists already. Then dot component props. And it should show up. There you go. All right. So hover over loader data.
JASON: Now it says contact record. Hey! So I can get rid of this.
BROOKS: There you go. Exactly.
JASON: Okay.
BROOKS: So now in our loader data, we should be able to map over it and use whatever the heck it gives us.
JASON: Okay. So we can say loader data.map. That's going to be a contact. And we're going to take this.
BROOKS: Yeah, just take one of the examples.
JASON: Let's see what's in here. Contact dot ‑‑
BROOKS: So I think we just have that ID.
JASON: So we need to kind of build one out.
BROOKS: Yeah, you've got it. Let's just do first, then another one that's last.
JASON: So that should get us back to where we were.
BROOKS: Should, yeah. Fingers crossed.
JASON: There we go.
BROOKS: All right. We got everything. That's perfect. Okay. Cool. That's all loading, which is really great. I assume ‑‑ I can't tell. Maybe click on one of those and let's see what, if anything, happens. We got a 404.
JASON: The ID is bringing up something different than a number. Do we need a different value?
BROOKS: That's fine. I think that's the ID it uses. It's just silly data. This is completely expected. Don't worry. This is what we wanted to happen. We haven't actually set up a contact.
JASON: Oh, right. Where would it be, right?
BROOKS: Exactly.
JASON: We need a slash contacts and figure out how to determine by ID.
BROOKS: Exactly. So you would use file‑based routing to set up your routes. You'd have a routes directory. We can do that. You can still do that in React Router, but we tried to take a step back and do something that's more similar to Ruby on Rails. If you go into that routes.ts file, this is like our config based routing. You still have to use files for your route modules. There's a lot of reasons for that. I gave a whole talk at React Miami about why we do that. I'm not going to go into the full details, unless you have specific questions.
JASON: Where would one find that? Is it on YouTube?
BROOKS: Fantastic question. I don't think they've uploaded it yet. I think Michelle said they would upload it by the end of the month. But hey, G2i, sponsors, get those talks out. The people are asking.
JASON: So here's what you do, everybody. You go follow Brooks on Twitter so that you don't miss it when that talk comes out, if you're interested in learning more about how all of that functions.
BROOKS: Man, what a professional. So seamless. All right. So we are going to make our routes. We could just make a bunch of objects. So if you make one, what is it, control space or whatever to see all the actions. You'll see it's already ‑‑
JASON: Yeah, here's our file. Right, okay.
BROOKS: Exactly. So we've added ‑‑ instead of building out that itself, we've added little helpers. So go ahead and delete that object and just write the word route, and we should get the import that we want. Oh, maybe not. Yeah, there we go. That first one. That's exactly it. Cool. Inside of that, it takes a path. So that's like the URL, like what we want to match to. Yeah, exactly.
JASON: Oh, Jesus. Oh, god. Okay. Spell it right. Contacts. Then what's the convention in Remix for variables?
BROOKS: It's going to be ‑‑ man, now you've got me second guessing myself.
JASON: Well, there's like three I've seen. There's dollar sign, colon, and brackets.
BROOKS: I know. I hate ‑‑ man, I hate conventions. I write this every day, and I don't even know what I'm supposed to do. Okay. It is a colon. The reason they do a dollar sign, I'm pretty sure, is because of like file conventions. You need something besides a colon, I think. So yeah, that's perfect. Then the second argument.
JASON: Second argument is a file. That's going to be ‑‑ do we need ‑‑ we'll just make one up and build it if a second?
BROOKS: Yeah, exactly. I would do pages slash contact details or something like that. And you can get rid of the relative at the beginning. I think it's fine to have that. I think it's a little bit better.
JASON: Just in case, yeah.
BROOKS: Yeah, just in case. I think it's okay.
JASON: Do we need any third options?
BROOKS: No. The reason you have a third option in this case is for two reasons. One, you can give it an ID, an identifier. If you're using this same route, like module, for multiple things, that's the automatic ID that it uses. So you need to differentiate that. The other reason is if you're doing routing. We're not doing that yet.
JASON: Got it. Okay. Contact details dot TSX.
BROOKS: Let's export a default component and return whatever you want. Let's just make sure this is no longer 404'ing. I guess that works.
JASON: Do you want it to be done a certain way?
BROOKS: I'm trying to think. I don't think it has to be named. This is more of a React thing, like named components show up better in React dev tools and whatnot. I know they're very pro naming all your components. But hey, whatever you want.
JASON: I like best practices. I assume that people who think about this a lot have probably thought about it more than I have. So let's go give this a shot. We're going to go into here. I'm going to click one of these, and it should say hello. It did nothing. Oh, that's because ‑‑
BROOKS: But it didn't go to a 404.
JASON: I have a hunch. You define slots in your layout. We didn't target a slot. So it's just kind of going into nothing.
BROOKS: Exactly. Okay. Cool. Yeah, exactly. So our slots, we like to call them outlets. So back in route.tsx, that's our only parent layout at the moment. Where do we want this? I think it's going to be in between those. Or is it after? No, go back, go back. We don't have one yet. That's why.
JASON: Like here?
BROOKS: I think you're exactly right.
JASON: So let's make an outlet.
BROOKS: All right. We've already covered loading data, nested layouts, setting up a route. So before we even fix the contacts, I want to show you something else that's pretty cool. Go back to your root.tsx file.
JASON: Okay. I'm in there.
BROOKS: You've got your hrefs. Let's change those to a capital "L" link.
JASON: That's not what I meant. Oh, my god.
BROOKS: You're good. There you go.
JASON: I just forgot what the shortcut was.
BROOKS: So we've had that for years. That's the reason React Router exists. So instead of that two, delete what's inside of it. Everything inside of the string we're creating. Yeah. Okay. Then open up the curly braces again.
JASON: Oh, it's going to be one of these?
BROOKS: Type in href. This is going to pull in a util. Just href. Yeah, yeah, yeah. There you go. Cool. And then open that up. Then if you start typing a string, it'll give you more options.
JASON: Oh, look at that. That's slick.
BROOKS: A lot of people might wonder why ‑‑ yeah, yeah, yeah. It is pretty cool. It's pretty sweet. Then you'll figure out the next piece of it. I'll let you finish this up.
JASON: We can autocomplete our way to victory here.
BROOKS: Exactly.
JASON: Okay. That's slick.
BROOKS: Yeah, you don't get this without some sort of framework compiler, the Vite plug‑in we have. You just can't do this stuff magically with just the library side of things. But we still need that library layer of it. So this is why we have all our different modes, more or less.
JASON: This to me ‑‑ this is the stuff that I want to exist. I feel like the part that's always hard with any type of building project is just sort of figuring out what's available. So the fact that I've written precious little TypeScript, like, this is the extent of the TypeScript I've written so far. With that one line, you know, my 20 characters of TypeScript, I'm able to do things like autodiscover what the available routes are and autodiscover the API for using this function. The thing that I think is so important is not that like TypeScript gives me the ability to very meticulously type all the things I'm doing. It's that it's allowing me to write code without having to know how all the code was written. It's discoverable. It's very ‑‑ like, you can intuit your way through by looking at these predictions. I think it's hard to overstate how valuable that has been in the world, to like see these little DX improvements come out.
BROOKS: Yeah, it's super cool. Honestly, TanStack Router was mentioned earlier. I'm super grateful for TanStack Router because it pushed a lot of people to ask for features like this. So yes, this is where, you know, competition ‑‑ it makes everything better.
JASON: Competition is a great thing. Whenever somebody gets sad that there's somebody else in the space, I'm always like, wait, but isn't this what we wanted? We want lots of options because that means that all of the good things that come out of all these options are going to show up in all the things we like too.
BROOKS: Exactly.
JASON: You can only stay stagnant in a monopoly.
BROOKS: And it's like if you don't like this, go be an iOS developer. It's great. They've got it on lock, and they're going to fight all these legal battles so you don't have competition. And you're good. But if you want freedom and ability to create a bunch of different things, then join us on the crazy web that we live on, and hopefully we'll have more than four websites again one day. But that's another conversation.
JASON: Some day. I believe in us. We're going to get to five.
BROOKS: Sweet. Okay, cool. Bluesky is trying its hardest.
JASON: I love Bluesky. That's where I'm spending most of my time these days.
BROOKS: Cool.
JASON: So we've got data coming in. We have this href helper. I believe we are client side routing now. I think I didn't need to do that, but I'm going to click this button.
BROOKS: We're not going to see anything change.
JASON: This is nice, though. So we're coming back. No page refresh. We're able to kind of move back and forth, and everything works. So that's good. What do you want to do next?
BROOKS: That's a good question. How much time do we have? Where are we at?
JASON: We are ‑‑ we've got about 35 minutes of coding left.
BROOKS: Okay, sweet. So we can ‑‑ there's a bunch of different ways we can go. We have a lot of things. Let's get this serverside rendering piece working. That seems important. So right now we are just doing client side routing. I think go back, and if you refresh, is there going to be a split second where it flashes? Okay, perfect. So that's because we're client side routing. If you use create React Router, this is the default setup. Client side routing, not bad. Rather, client side routing only. And by routing, I mean rendering. Sorry. It's not necessarily bad, but for a lot of websites, we don't want that flash the first time people go to it. We want everything to be generated on the server and sent as HTML.
JASON: And we want websites to function without JavaScript turned on. Like if I load a page, I want it to work.
BROOKS: Yeah, exactly. Yes. And the reason why, this is a ‑‑ remix was really big on this early on, the whole progressive enhancement thing. So this is a thing that I'll mention and people will respond to me and say why in the world ‑‑ who's turning their JavaScript off? So just a quick, you know, aside here. Very, very few people actually turn off JavaScript and navigate the web. It's not about that. It's about you don't know when JavaScript is going to be ready. Unfortunately, there's this whole ‑‑ uh‑oh. Did we lose him?
JASON: No, no. I'm just giving you the platform. This is you on your soap box.
BROOKS: Oh, this is amazing. Cool. Oh, man. I lost my train of thought. So the problem is we have this thing called the network. We can't control that. We can't control where our users are. We can try and control how close our data centers are use something like Cloud Flare and you have durable objects everywhere around the world, but you have no idea where they are and if they're entering a tunnel or are going to lose connection. So you want your website to be resilient. We want things to be resilient in general in technology. Backend applications, we make those incredibly resilient by having multiple different versions so there are these fail safes. If one service goes down, a new one can restart. This is why serverless got really popular. If you have an e‑commerce website and you want your users to be able to buy the new shirt that you just released, even if their JavaScript has not fully loaded yet, that's going to be a better experience, and you're probably going to sell more T‑shirts. Anyway, this is why we want progressive enhancement. It's not because people are navigating around by turning off JavaScript. Yeah, soap box over. Thank you. I wasn't prepared for that. I should have written something.
JASON: No, no. It's all good. This is the thing I always love. When you look at something at the surface level, a lot of times it feels silly. Of course people have their JavaScript on. But I frequently experience moments throughout my day where as I'm leaving my house, you know, my Wi‑Fi drops and I don't have good cell coverage. So the website I'm looking at fails to work. I have to wait until I'm further away from my house and I have better cell coverage to do the thing I was trying to do. That's not like me choosing to turn off JavaScript. That's the network choosing to turn it off for me. Right?
BROOKS: Yeah, yeah. Definitely.
JASON: So we want to be resilient to bad connection scenarios. We want to be resilient to weird blips and all these things that can happen. The other thing, too, is it also just makes the experience of using it with JavaScript better. Like you said, there's a half‑second flash. If we don't get the half‑second flash, my experience improves.
BROOKS: Yeah, this is what was so fundamental to me about Remix. We're probably not going to get to forms. We talked about those a little bit. The way Remix said like, hey, we're going to start with the foundation of multipage apps in the way the web was built. For me as a relatively ‑‑ you know, I came into web dev When React was in full swing. We were on click everywhere. It actually was really helpful to go back and understand what is the fundamental layer I'm building on top of how the web actually works. Thinking in that paradigm and enhancing it is actually going to ‑‑ it's not just going to make things more resilient, but it's also going to make you a better developer. You're going to understand the platform you're building for. It's going to allow you to do a lot more than you could before. You're not going to be in this narrow box of everything has to be react and you can only think in versions of React. React is great, but there's a lot more outside of React. And React will be the first one to tell you don't do everything in React. But anyway.
JASON: I think a lot of times people get hung up and say it's gatekeeping to say people have to learn the platform. You never need to learn anything. You don't have to ‑‑ especially now with the way that AI is going. You probably never need to think ever again. However, your life will probably improve if you do, right? You always have the choice not to learn. But you also gain advantages by doing so. So it's not that we're saying you must do it or you'll fail. We're saying you're going to have a better time if you choose to learn.
BROOKS: Yeah.
JASON: So yeah, not gatekeeping. Just gentle encouragement. You got this giant brain muscle, and it's so good at learning things. If you let it do that, oh, man, how good is life? It's just fun to know stuff and be able to do stuff. Can't recommend it enough. Anyway, you want to write some code? (Laughter)
BROOKS: All right, let's do it. Yeah. Sorry. That was a lot of soap boxing.
JASON: Oh, my god.
BROOKS: All right. Thank you. You said it way better than I could have. Let's serverside render.
JASON: Let's do it.
BROOKS: All right. Go to react router dot config dot ts.
JASON: I have a hunch.
BROOKS: All right.
JASON: Is that really it? Is it just do it?
BROOKS: Well, let's see. Save it and let's refresh. We still got a flash. But it is actually technically serverside rendering still.
JASON: If I turn on JavaScript, we'll still get a page?
BROOKS: Maybe try it. Let's see.
BROOKS: Also, let's open up the network and see what's coming in. All right. Give us a refresh. What do we got? A bunch of stuff was blocked. That makes sense. We got John Jensen. Let's look at that.
JASON: We got that. Here's our response.
BROOKS: Okay. So we actually did serverside render. We got HTML. We got something back.
JASON: We did.
BROOKS: But we didn't actually get anything back. So the reason is, is because if you go back to our root.tsx file, we were using a client loader. So you can use client loaders. They don't run on your server.
JASON: But they're still running on the loader. It's always on the client.
BROOKS: So we turned JavaScript off, which means we don't actually get ‑‑ this can't run. This is JavaScript. If we change this to a loader, this should all just work correctly. It partially works because our data source is kind of cheating. There we go. Perfect.
JASON: This is great because this shows the difference between, like, if we're not doing a client‑side fetch and we're doing serverside rendering, then when ‑‑ like, obviously any complex app is not going to actually work with JavaScript disabled, but the idea that if I'm just trying to check my account balance, I can do that. I might not be able to initiate a transfer. I might not be able to do all these other things. If I'm trying to figure out do I have enough money, can I make a withdrawal from this ATM and I'm on 3G, I just want to see that number. There's so many little things that are just much nicer when you ‑‑ oops. That's not the button I wanted. So let's turn this back on. Enable JavaScript. Now we don't even get the blip. So the client loader solved our blip.
BROOKS: Yep, exactly. So we have loaders. We have client loaders. You can even inter‑op those. If you wanted a client loader, it can be in charge of when your server is called. You actually have a bunch of different tools to build up whatever you want, but it's still just this idea of these layers of loader, client loader, if you have one, component. You trigger an action. Action. Client action, if you want one. And that goes through. Then more recently, we've added middleware. Maybe we can try and get some middleware going. That's one of the fun new features.
JASON: I think there was even a question out here. Is there plans to handle middleware so we don't have to have multiple auth checks and nested routes? Looks like the answer is yes.
BROOKS: Not only are there plans, there are features. Cool. So this is ‑‑ I am going to have to pull up some docs for this one just to make sure I know exactly how to do this one. It's still unstable. The way we release new features, we release first unstable, meaning this API could change between versions. When we're happy with the API, we'll release it in a minor. If it's purely just new, we'll release it in a minor. If it's a breaking change, we'll release it in a minor with a flag. So that's kind of the idea. So let's go to our route.tsx file. We're going to make ‑‑ this will just be top‑level middleware. You can put middleware wherever you want in your entire tree. So we're going to export a const. We're going to call it ‑‑ man, where's my example? It's going to be unstable underscore middleware.
JASON: Okay. Is it async?
BROOKS: Yeah, it's going to be ‑‑ well, it's going to be an array. Because we could have multiple.
JASON: Oh, got it. Okay.
BROOKS: So give me one second. I'm trying to pull up my docs. I can't find them. Here it is. All right. Perfect. I forgot, we actually have to do one more thing. Go back to our React Router config file. Then here, type future. This is how we enable all our future flags. Perfect. We got a bunch, but we want the middleware one.
JASON: Got it. Yeah, I like this convention. Cool. Okay. So we've got that. Then back in here, we're exporting some unstable middleware. To do that, we're going to add in a function.
BROOKS: Yeah. So we can just inline it. That's probably the easiest way to do it. You can do it as ‑‑ yeah, either one.
JASON: Why not. We'll do it this way.
BROOKS: We can get some type safety here too. This one is not my favorite, but once you get it set up, it's good. Let's annotate what unstable middleware is going to be. So do colon and then the route, capital R. This is also type change. Then there should be an unstable middleware something or another. There we go. That one. Then it's an array. So let's put the brackets at the end. All right, cool. A little bit of ceremony. That makes it ugly, but things will be typesafe. So in here, what we're going to do, we're going to do a very, very simple middleware that's going to basically measure performance in our application. Very simple. When were things initialized, and when did we finish handling all the requests?
JASON: Okay.
BROOKS: So let's create a variable called start at the very beginning. We'll do performance dot now is perfect for this. Cool. Then let's do the end. Just finish both pieces of it so we know what we're doing.
JASON: Same thing?
BROOKS: Exactly. That'll take a measurement once, twice, and then let's console log something that says, like, hey. Yeah, let's do console log navigated to. Then just add the time, maybe a dash, dash. Then we'll say what the difference of the duration was in milliseconds.
JASON: Okay. So end minus start.
BROOKS: Perfect.
JASON: Is that right?
BROOKS: Milliseconds.
JASON: Sorry, I forget how performance dot now works. Okay. So to get this, I have a hunch you're going to give me a helper in here.
BROOKS: You got it. So open that thing up. Curly braces. Then you got a couple things. We're going to want the request. Perfect. Then we'll just use ‑‑ it's just a normal request. It has all the request‑y things on it. URL is probably the best thing to use in this situation. I think it'll parse it. So what do we actually want to measure here? We want to actually measure everything else that happens. Basically, middleware has all happened synchronously or like one after another. Then all your loaders run. So there's actually ‑‑ just like if you've ever used express, you get a next function. That's pretty typical. So the next function is actually the second argument to the middleware. So it's not in that curly braces. There's reasons for that. I'm not really going to get into it, but it's right there. So what we're going to do is just call await next. Exactly. And we want to actually get the value returned here. So let's save this to something like RES for response or whatever you want it to be called. That's perfect. And we need to make sure at the very end of all this we return that response. Because we do ‑‑ this whole chain needs to return. Everything needs to keep returning responses. If you don't do the await next thing, the middleware will automatically do it. So you only have to do this if you're trying to do something in between like a response happening. Otherwise, you can run stuff in middleware and the response stuff will be handled. So don't even worry about it. But we specifically want to say start timing, run everything else that's supposed to run. Oh, that's all done? The entire thing has come back up? All right. Time again, print that out, and return this.
This is way less exciting without setting up that data piece. Perfect. Now we have really simplistic timing and whatnot. The nice thing about these middlewares is because it's just this function, people can create their own middlewares and import that as an npm package. So Remix has a great community package that I think has like ten different middlewares. Yeah, let's go to it.
JASON: This one here?
BROOKS: Yeah, Sergio. Exactly. If you scroll to the complete bottom of this entire document ‑‑ it might take like 30 minutes because it's a huge document. Perfect. You're seeing already, yeah, there's this honey pot. Go up a little bit, but we'll start seeing all the middleware stuff in a second. So a honey pot middleware. There's some cookie stuff. So they've already created a bunch of patterns in this library for just middleware you can plug and play for authentication, for session management. We didn't even talk about context, but we have a nice typesafe context feature now that they've built. Even if you're trying to understand and get your mind around middleware, this is a better resource than our docs currently are. So definitely worth checking out.
JASON: And just as a reminder, if you're in the Code TV Discord, we have a channel called ‑‑ I think it's called links, that will automatically import anything I'm sharing. So all the links from the show today are going to be posted in that channel, if you want to go check them out. All right. So we have some middleware. We can see that happening. You can kind of imagine we could also do something like if there's a valid session for the given user, then we return next. Otherwise, we would redirect to the login page. So little stuff like that gets nice and easy when you've got a good middleware pattern. Do these execute on the server side or only in certain contexts? I know there was that whole thing about the Vercel middleware. Does this work the same way? I guess I don't know enough about how any of these are implemented to answer this.
BROOKS: That's a fantastic question. First of all, to answer the first part of that question, go ahead and go to ‑‑ navigate to whatever route is, that type we've been messing with. No, not in here. That was confusing. Sorry. Within the code. Line 22.
JASON: Line 22.
BROOKS: Yeah, that guy. This is auto generated. This kind of shows you everything you have or could have in a route module. So you can see here on line 33, we have client middleware. It follows the same convention. You can have ‑‑ a middleware is all serverside. If you want client side, like you want to set up a client side cache and do it once in a middleware, instead of having to think about setting it up in every route, or if you're doing your authentication on the client because you haven't migrated to something serverside ‑‑
JASON: You're like literally SPA only. You can use that.
BROOKS: Exactly. So you have both environments. You can't do the middleware stuff. The stuff we did is on the server.
As far as your question about security stuff, that's a great question. We've had security issues. We had some similar ones we had to create a CWBA, I think that's what they're called, relatively recently. The problem with that is it's not related to middleware itself. It's implementation that handles headers. I'll talk about ourselves. We use some headers to handle prerendering. We were using headers to signal that. Someone pointed out to us that's actually a really easy way for someone to spoof and say, hey, pretend you're prerendering now, and it would just completely ‑‑ you could just blow up a page, and it would poison the cache for everyone else. It would get cached in a CDN if you did it at the exact right moment. You could also theoretically run some nefarious code with these things.
JASON: You can make a mess out of it.
BROOKS: Yeah, so it's really that level where security concerns come in. The fact that middleware exists, you can now create your own security risks. You have full power to do that. But it inherently is not. It's just another function we're calling on the server, just like your loader. It's really just about coordination of when it runs versus when your loader is running.
JASON: Okay. Great, great, great. So that makes sense. What else do we want to dig into, knowing that we have how many minutes left? Like ten‑ish. A little more.
BROOKS: Yeah, that's a great question. I'm trying to think what's worth going into.
JASON: And chat, if you have questions that you want to see us dig into, please do drop them now. This is probably your last chance for us to dive into something on stream without sending you to a doc or something. Things that I would be interested in seeing, can we just really quickly run through the process of extracting that parameter and showing maybe just the person's name
BROOKS: Yeah, let's wrap that up. Let's create a loader. It needs to be out.
JASON: And probably there's like a get contact.
BROOKS: You got it.
JASON: And that contact is going to need an ID. My ID comes from here.
BROOKS: Yes, exactly. Let's type it. On the right‑hand side ‑‑ not that part. Still within, we're just going to type the args. So this will help with how the type safety works. You can see it's already suggesting things. It's going to be that second one. I'll kind of explain why. So the way this works is that plus types is kind of the signal that ‑‑ yeah, you got loader args. That's a signal this thing is type generated. Then the fact that it's relative is just the way we've set up TS config where it always is aware of exactly where you're at to try and make this really simple. If that's over your head, don't worry about it. We have docs that explain all that stuff. But Jason is doing the right thing here.
JASON: So we're going to get our contact. I'm going to return this contact. Then up here, I'm going to get my props, which will be the route. That was component props.
BROOKS: Very professional. This is perfect.
JASON: I remember. So then down here, I should be able to ‑‑ I guess we could just say loader data dot first and last. I screwed something up. Can't find module app data imported from contact details. So what did I miss? App data.
BROOKS: Oh, you know what, VS Code's default is really dumb. Just remove the app part. That's VS Code. I don't know why it automatically assumes these sorts of things.
JASON: So now we can pop around, and we actually see people's names. So look at us go, everybody.
BROOKS: And if you go back, there's actually one little detail that was skipped over.
JASON: Oh, yeah.
BROOKS: You may notice those params were actually optional, on line 13. So why is that? Let's look at line 7. What is contact?
BROOKS: Oh, we have an optional.
BROOKS: Yeah. So the reason is because technically we have no idea. We're not going to throw, or at least we weren't, if this ID doesn't exist. We're going to say, hey, this doesn't exist. It's nulled.
JASON: So I can break this right now if I ‑‑ because I wasn't cool enough to make this list. We've now broken the app.
BROOKS: Yeah, it's like what's happening. What we want to do, we want to be good web people. We want to do how the web is supposed to do, and we want to return a 404 response. We're going to say, yeah, if no contact, and you can just return or throw. Either one is fine. Exactly. Then the body, just say ‑‑ I think it's whatever the docs would say. It's just a string is fine. Do like not found. Oh, this is perfect. Even better. There you go.
JASON: Wait, what am I looking at?
BROOKS: Hold on, hold on. This is the returned response. Go to constructor. You see on the left‑hand side? Try that one. It might give us a better example.
JASON: Okay, okay. We need a status and a status text. So we're going to return a status, 404. And status text is not found.
BROOKS: It's still lying.
JASON: Don't you lie to me. Only specify known properties. What?
BROOKS: Okay. I think change it ‑‑ I'm looking at the docs. No, no, no. So, change the first argument and response to just be a string that says not found.
JASON: Okay.
BROOKS: You can delete that.
JASON: So theoretically, it would be like this. So that should get us our actual ‑‑ and it won't change anything here, but it should show us out here, maybe. It is, in fact, a 404. There's our 404.
BROOKS: This is actually pretty easy, yeah.
JASON: Where do I go here? So these are still a 200. Okay.
BROOKS: Export a function called error boundary. It'll be a component. Inside this module. Doesn't matter where. Perfect. And we'll just do something generic at this point. You can get all the status code and everything, but let's just return ‑‑ we'll say not found. Just pretend we're doing the checking. Yeah, exactly.
JASON: So now if I try to reload this, nothing happened. That's because ‑‑ did I typo this?
BROOKS: No, this one's on me. I'm not sure why it's not doing ‑‑ try ‑‑ maybe it truly is for errors.
JASON: Do I need to throw?
BROOKS: This is a great question. Try throwing. Otherwise, I'm ending us on a horrible note. Throw it instead of return. Yeah, you can certainly do an error. So that works. We still want it to have the 404. I'll have to do my research to remember.
JASON: Yeah, we'll ‑‑ I imagine ‑‑ yeah. I don't exactly know how all that works. So that gets us close. So what we would say is to figure out how to show 404 for a response, which I imagine is right there in the docs.
BROOKS: I'm sure it is. Oh, man.
JASON: Again, that's definitely ‑‑ actually, that's a good point. We never blame the guest. It's always my fault.
BROOKS: Good to know. I mean, you did exactly what I told you to do.
JASON: That is great. This is great. So just to kind of recap here over what we were able to cover in, you know, including soapbox time, I think we spent maybe 45 minutes actually writing code. We got ourselves set up with some custom routing. We got data loading from the server in this case. We also originally were loading it client side. We are using that data to populate the page. We're doing client side routing with the link that falls back to serverside routing in a progressively enhanced way. We're using this nice little helper that can identify which ‑‑ or it lets us know which routes are available and autocompletes those for us. We also are able to use middleware to do some stuff, like in this case check how long it took us to load the page. Then we were able to set up in our routes a route defined by this helper function that tells this is how the href knew what was available. Because we defined this here. We set that up to a page. That page has contact details, which includes another loader that's using the params passed into the page. That's the ID that's being passed in. That is able to also run a load to get the appropriate contact, display that on the page, and we've got this error boundary that allows us to do something correct if there is a problem with the data that we're trying to display. That is a lot of ground to cover. I mean, if you've been writing React for a long time, think back to how much work this would have been even five years ago. And how much is just kind of done for you in a framework like this. This is a really, really nice quality of life enhancement. I have worked on React apps since before React was the dominant framework. The number of things that are just problems I don't have to solve anymore because they've been standardized in frameworks is pretty staggering, honestly.
BROOKS: Nice. That's a way better assessment than I could give. So, appreciate it.
JASON: So, Brooks, what's next for people here? If they want to go further, want to learn more, they want to get their hands dirty with React Router and Remix code, where should they go?
BROOKS: Yeah, that's a good question. Really, it's been here the whole time. This tutorial is the first place to start. If you haven't messed with it at all, if you haven't learned, definitely start with this tutorial. If you are already familiar or you've gone and done that and you want to engage with the community better, the best place to engage is on our Discord. The URL for that is just going to be ‑‑ it's just rmx.com/ ‑‑ I think this is right. Let me check.
JASON: Rmx.ax.
BROOKS: You knew it already.
JASON: I didn't know it. I did copy/paste it from your docs.
BROOKS: Beautiful. All right. Perfect. Then I will plug this, just because this is a thing I work on every month, and I'd like people to read it, if they have time. Rmx newsletter. We have some announcements in the works. We have a conference we're hosting in October and will be selling tickets to shortly. This will be the best way to find out about those.
JASON: Nice. Awesome. Well, Brooks, thank you so much. Let me do one more throw to your ‑‑ I guess to your Twitter because that's what I have open. Make sure you go give Brooks a follow. There are a lot of good things coming out. I know you mentioned early on, you hinted at some announcements, maybe new developments we should be paying attention for. I know you had talked a little bit about there's some RSC experiments, maybe some upcoming work with Remix and RSC. So if you want to stay up to date on that and maybe even dig into the experiments, you know, go follow Brooks and make sure you're on that insider route. So that being said, this episode, like every episode, has been live captioned. Thank you so much, Rachel, for being here from White Coat Captioning. Thank you, G2i for making that captioning possible. And again, if you are hiring, go and talk to G2i. They're great. I know a lot of the folks that work there personally. Enjoy them very much. And if you're looking to build something on the internet, give Remix a try. That being said, we have more coming up that is going to be super fun. Make sure you head over to the Code TV website. We have new things coming out all the time, but the next thing we got is we're going to be revisiting ‑‑ let's see. You know what, we might even have something next week. I don't know. I might be traveling. I can't remember. We have lots of good stuff coming up, including part two of building a game in TypeScript with Will King. That's going to be super fun. Lots more that I still need to get up on the website. So, as always, thank you all for hanging out. I hope you learned something. I hope you had a little bit of fun. And we'll see you next time. Thanks so much, Brooks.
BROOKS: Thank you.