 Hey friends, I'm Jantastic and welcome to the week three React app directory beta recap. Today, we're actually just building an application. We're gonna take everything that we learned, but not everything. We're gonna take the most important things of what we learned and actually building out a page. And we're gonna set up a little tiny Pokemon app doing like the data fetching thing and using a next image and next link and seeing all the cool optimizations that you get for very little effort. Cut the chit chat and dive right in. Okay, so first things first, we're gonna go to beta.nextjs.org. This is where we have all of the app directory beta documentation. If we click the menu, we'll see getting started installation and we can just copy and paste a command right here. And we want the latest and experimental app flag. So we'll run that, Pokedex TypeScript, nah, not today. ESLint, yes. And then we'll open Pokedex in code. We'll open up a terminal and run npm run dev. Then visit our local host, localhost 3000. Now to add pages, we know that we need to add a page.jsx file at the sub-directory that we want it to appear. So let's make a new file at pokemonboldbessor slash page.jsx. Here we export a default function, turn some, let's do a main element, then an h1 with the text Bulbasaur. I think I spelled that right. I always get that one wrong. Okay, now we can visit this here at Pokemon Bulbasaur. We're getting through to that through the Pokemon Bulbasaur page.jsx. That's what we're seeing right here. Now we can customize this with dynamic segments. Let me show you kind of how that works. I'm gonna close this, open this a little bit more. And we're gonna rename this to create a variable. And we do that by just putting brackets around this director name. Now here Bulbasaur wouldn't make a ton of sense. So I'm actually going to assign that as name. And now name will come in on our params object. Okay, so now we have Pokemon. Name is a dynamic segment and then our page. So let me close this sidebar over here. Destructure params off of my props for this page. And use that instead. So use params.name. And if we reload this, we have the same thing as we did before, but now it's dynamic. So we're gonna say ditto and we'll see ditto. Good so far. So let's find some data to get on these Pokemon. I'm gonna go to poke at api.co. Go down here and we'll see this URL that we can grab. So I'm gonna copy that and paste it in here. Yep, that's it. Pokemon equal await fetch of this URL. Let's make this a template literal string template. I can never remember the names of these things. Do that, make this dynamic using pokemon.name. And we have an error here. Now we know that that means we need to change this function to an async function. Now we have an async function component. Now if we wanna use the data that we're getting, we need to change this from params to pokemon. One last step, we need to process this. So change this to request or response and pokemon response.json. So close this and go back to localhost. Let's see what we get. Can't read pokemon before initialization. Let's refresh that. And I just misnamed this. I need this to be params, params.name. And I always forget this step. I gotta await this as well. So now that we have that, it works and we can look at our network and see that there were no fetch requests to the poke API endpoint because that all happened on the server. Now because we're required to use this page file for any route that we want a page at, we can actually co-locate other JSX or JavaScript files inside of these directories without them turning automatically into pages. Now I'm gonna add a pokemon file inside this. So pokemon.jsx. I wanna pull this out into its own function. So we'll put this over here, export, default, get pokemon. And we'll take a, let's just call this identifier because I think we can grab them by number or name, return await, response.json. And we'll change this to I, and I totally forgot to make this an async function. So we'll do that. Now actually I wanna send this out as a named export so it'll be on get pokemon instead of the default. So let's save that and update our call over here to get pokemon with prams.name. Of course we need to assign that to a variable so let pokemon equal get pokemon. And we should have the same response. Again, these awaits always kill me. I gotta wait that and then we get it, then it works. Now what if we wanna add a list to this view as well? We can do that, add a fragment and put an aside here. In it we'll do an unordered list. And I'm gonna write the implementation that I plan to have. So we'll have a pokemon collection that we'll map over. And to map over it, I'd like to use another function from this pokemon module list items from pokemon collection. And we'll call that as a, I don't know, zero point something, zero point call. What is that? I don't know what the terms are. I just know zero point something. And close that up. Okay, and we got that. So now none of that's defined so we can define that real quick. So we're gonna say pokemon collection is going to hit that same endpoint but without any parameters. And that should, I'll put a default in here just in case. And now it's barking about a list item from pokemon collection. So we're gonna define that. This will also be exported export function. This will take a pokemon and return a list item. So we do list item, key is pokemon.name and list the pokemon.name. Okay, we're gonna take one last step here and actually import that list item. Zuh from pokemon collection. Save that dot map. And actually in this API, these are under results. Perfect. So now we have this list of pokemon and then also a pokemon name. So we have like a list and then a show. Now I don't particularly like this layout. So I'm gonna next add a layout file. We can close this, open up our sidebar again and inline at a layout.jsx. Now here I'm just gonna paste in a layout file because you don't wanna watch me write a bunch of CSS. It's terrible. But what this does is it adds a style. We have a simple grid that just has two columns, a 10-rem column on the left here and then the remainder is on the right. So this space over here. We can make this whatever we want. So here maybe we want a little bit less space, close that gap in a little bit. And then I just have a little bit of padding around it. Otherwise we just take the children and render those out and these children are going to be this page. That's cool thing about layouts you can just insert them afterwards. Okay, the next thing we wanna do is actually link to these Pokemon right now. We still have to type in the URL manually. These are not links. It's just a list of the first 20 Pokemon. So let's get into that. We'll go to page. Our iterator is in this Pokemon file. So I have to change that right here. We wanna wrap this in a URL. So ahref equals, we want this to be dynamic as well. So string literal, we'll do pokemon.name and we need to hit that Pokemon sub directory first. Okay, close that up and see how we did. So save that. Okay, cool. So we see that URL at the bottom down there and we can click on metapod, war turtle, squirtle, charmillion, awesome. So now this is fully dynamic because we have that link. Now in the next app, there's this next link that we can use which is actually pretty great. So let's change this to a next link. So import link from next link and change this from an a tag to a link tag. Okay, now, not much is gonna change visually. I'm gonna restart this just so we know that everything's in there. And when you click on stuff, it is a little bit snappier. You might have seen that it responds a little bit quicker now, which is cool. And let me show you one of the reasons that it does. This is honestly one of the coolest things to see. So if we go to the network page, when we look at the fetch requests, as I scroll over the ones that we haven't looked at yet, we'll actually fire off requests to get the server component, I don't know, data for that page. So it's firing off all these requests as we hover over the links. And then when we click it, it already has the data to fill that page in. Now, if you haven't seen it before, this is what server component data looks like. There's a protocol with all these kind of IDs. And then, you know, children, name, Pidgeot, we're not getting a page, we're just getting these instructions on how to update the page that we already have. But it is all still powered by the URL. So you're not gonna get in a weird state that you can't recover. So what's another thing that we may want? Well, we probably want to have an image of this Pokemon. So let's go back to our page. And in the main portion, paste some code for an image. This is just a regular old image tag. Just like A, we're gonna start with that and then upgrade it with some of the next cool features. Okay, let's save this. And we see an error or a warning and we'll come back to that. And we're seeing these in right away, which is really cool. That was fast, easy, painless, no problems. Now, about this error, so let's check this error warning. About this warning, let's check it out. What does it mean? Image could result in slow LCP and higher bandwidth use image for next image instead to utilize image organization. Okay, so let's do that. Just exactly what it says. Let's switch to image and see what happens. So we get an error. Your image is not imported. Image from next. Image, no problem. Okay, it's getting a little pickier now. So image with source is also gonna require some other properties. One of the ways that it does some of its optimization is by knowing explicitly how much space it should take inside of the eventual DOM. So we're gonna give it some numbers. Width will be 96 and height will also be 96. We have square images that we're working with here. So finally, there's one last thing you have to do if you wanna use next image with remote images and that's to set up some next config. So let's open up the nextconfig.js. I'm just gonna copy and paste some stuff in here. So yeah, so we just add this image property inside of it a remote patterns which will give an object for this one remote source. You're gonna have to do this for all of the remote sources that you use. You have this glob at the end there. So no matter what the file name is, they're all gonna be included under this one declaration. Okay, let's save that. And I think we're gonna have to restart the server in order to get the benefit of this. Kill it and restart, see what happens. There we go. Now, I wanna show you what we actually did. So if we open up this and we inspect this element, so this is pretty wild actually. So we have our alt text and let's see our image or source right here. And that's providing an optimized image URL for the source image, just directly the source image. We have a decoding async, a loading lazy and a couple other properties. These are designed to make sure that the UI doesn't block on loading these images. So everything else should load even if these image files end up being like really big and hard to download. That's that. We also get one X and two X variants of this depending on the screen resolution. So really cool stuff that's happening behind scenes. And we just have to do the two things, use the image tag and then update that configuration for the remote endpoint. Now, I wanna show you something else that's kind of important. So if we go to our local host, it's gonna show this instead of our page. I'd like to direct people to the Pokemon, first Pokemon page. So how do we do that? Well, there's a redirect in next navigation that we can use. Let's open up our page here. So this is the root page. So I'll just paste in what I have and kind of tell you what we're doing. So we're importing the named export redirect from next navigation. We're gonna export a default function which is gonna call that function to navigate to this particular URL. Now, we can daisy chain this if we want. So we can have this one just direct to Pokemon. Pokemon doesn't have a default. So let's copy and paste that again. Add a page to our Pokemon route. So page.jsx export the same thing, but this time with Bulbasaur, which is Pokemon number one. You can handle this a myriad of different ways. Yeah, let's save that and go back to our root. We should see Pokemon flashed in as Pokemon and then eventually redirected to Bulbasaur. Now redirects are gonna be critically important in the upcoming lessons. So keep an eye out for that. Now, one last thing that you need to know is that I have tried really valiantly to get pagination in here. So this is just the first 20 Pokemon. I wanted to have a load more or some type of like pager that would allow me to do the next 20 and the first 20. And I needed to do that using search params. So something like limits 100. So we just kind of keep increasing the limit. Unfortunately, I learned that next layouts don't actually support that. So if I go to page.js and we'll see that it takes params as well as search params. And if we go to layout.js, go down to the props, it takes children and params, but no search params. So I get access to the dynamic segment, but not the search params, which means that I can't do the pagination inside of a layout file. So this is the idea of parallel routes. And so this is an idea that you would have kind of two pages, I think, that could respond to the same data, in which case we could kind of segment the aside and the page and handle those differently with both having access to the search params. But this is like just in planning phases right now. So at the moment, we have to do a lot of complicated stuff stuff that I really didn't want to do today in order to get that pagination to work inside of our page. And it's a little bit disappointing. All right, so that's it. We covered a lot about page and layout and we kind of skipped over special files, but you get the idea there from our previous videos, which you can watch here if you want. And then we covered link and image and talked a little bit about how irritating layouts are at the moment. So hopefully those get better, but we'll see. Anyway, thanks so much for hanging out. I'm really excited. We're getting really close to the end of this thing. We've got like three or four lessons left. I really can't wait to share more with you as we talk about mutations and data fetching and sending. All right, that's it. I'll see you later. Peace, bye.