Incrementally adopt the Next.js App Router

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so you want to try out the next JS app router but you're not sure how to incrementally adopt it well this video is for you we're going to walk through some practical strategies of moving over routes from the Pages directory to the new app directory let's get into it all right I've got a new nexgs application set up from create next app and let's take a look at moving over our first most basic route from the pages router so in sign up pages I have a file called static.tsx and inside of this file it is exporting the function that has a title and a paragraph pretty simple it's not using any state or effects this is purely presentational so let's move this over to the app router I'll start by going to the app directory I'll make a new folder static and then I'm going to drag this file static.tsx into the new folder you'll see I get a 404 in my browser because the route no longer exists and I'm going to rename this from static to page page is this file convention that next.js is looking for inside of the app router to know that it's a piece of UI that I can route to so I hit save I rename it and you see that the new route shows up in my browser now it's subtle but we actually just moved from a client component which is how all of the next.js pages router works to a server component now react server components are the default in the app router which means that for this route we aren't sending any additional client-side JavaScript for what we're rendering out here on the page which is basically just some HTML now this is of course the most basic simple application so let's go a little bit further all right let's move over our next route so I have Pages slash client which renders a button that increments some value and then displays that value on the page so in my browser at slash client if I click on this button I see the value increment so this is just a simple react component that uses some State let's move this over to the app router so again I'll make a new folder here we'll call this clients and then I'm going to move this client file into the client folder again we'll get the 404 I'm going to rename this to page and we should see an error now what this error is saying is hey you're using state or effects or other things that work in client components and you're trying to use it inside of a server component so instead what you need to do is to tell an xjs and tell react hey actually this is a client component so we're going to add this use client directive on the top reload the page and everything works just like before this is really a key point to hit home because for a lot of libraries that you might be using they might be built on top of hooks that use client-side react so probably the easiest way to incrementally adopt or move things over is to start using use client now I have a video in the description if you want to learn more about client components they're not bad you shouldn't feel bad using them and go check that out for example I could actually take all of this code and I'm going to make a new file inside of this folder let's call it counter.tsx and this is one difference from the pages router which is I can actually co-locate my components along with my pages so let's call this export default function counter and this is basically the exact same thing from before but let's get rid of this and we'll get rid of this and we'll also get rid of this so it's just going to be actually we're going to need to keep the fragment here so it's just going to be the button and the paragraph that shows what the count is this is this self-contained counter component now note that I removed use client and you're going to see why so if I go back to here and actually get rid of this part and we'll do counter we'll import from counter here and I can get rid of this state I can get rid of this but I keep use client in the entry point into this route the top level hit save reload my page everything works exactly the same so even if I have 10 15 100 different components that are being rendered from the top level I don't have to add use client to every single one of them I'll put some links in the description as well too if you want to learn more about this one last thing here that might take a little bit to get used to but client components can actually render server components so if you think of server components as really the presentational parts of your UI and the client components as the interactive pieces you can do something like this so let's say that your counter took in some children and then let's say maybe we render those children down here cool and for the sake of this we're just gonna plop this one as a react node here awesome now back in our top level server component what we could do is we could say you know what this counter except some children and this is going to be my server component now up here we could Define some function my server component this is going to return yeah that looks great we'll go with that we could do something like this the last thing here is that we need to move the use client directive from the top level of this route down to the counter component which is actually using some client-side state so if I go ahead and add use client into our counter component and I go back to our page now the page or the top level entry into our application is now a server component so now both the default exported component here and my server component are both server components but the increment button which has client side react State still works as expected and now there's this weaving of client and server components which is really showing the benefits of this architecture you can take advantage of the best parts of the client with interactive applications and the best parts of the server like fetching data which we're going to show in a second and displaying some UI remember that client components are like the pages router inside of nextgs which means they still get pre-rendered on the server instead you're you using the client to add interactivity to your application and actually make this button update some count because it has some state so when you actually open up the HTML here you look at the dev tools you will see the HTML pre-rendered from the server on the initial request okay next up let's talk about moving over the next head API for setting meta tags over to the new metadata API inside of the app router so inside of pages slash head I have basically the same component as before but I've defined the next head component that has a title of my page and then a meta tag with the description so let's move this over to the app router as well too I'll go ahead and make a new folder again we'll call this head and I'll move this file over into here you're getting the hang of this by now I'm going to rename this to page and now you'll notice that in the browser it says create next app it doesn't say my page and that's because next head does not work inside of the app router so instead what we want to do is we want to export const metadata and then this is going to take in a title my page in a description my page description so I can go here I can get rid of this get rid of this if I hit save now if you go and look at my browser you see that the title was updated I can pull up the dev tools here and look at the head and there we go I see the meta tag of my page description as well too now this is the basic example you can also do Dynamic metadata when you need to actually read some of these values from a remote location I'll put a link to the docs for the generate metadata function as well in the video description now things are starting to get interesting let's talk about data fetching so in this route Pages slash SSR we're going to move over a route that was previously using git server side props into the app router now there's there's kind of a lot going on on this in this file here we have get server side props which is making a request to the GitHub API it's getting back information about this repo as Json and then it's returning it as props to the default exported component here of page now to make this work well with typescript you have to do a little bit of next JS magic here you have this infer get server-side props type which basically means that when I'm down here inside of my component I can do repo Dot and it knows that the two fields are name and stargazers count now there's kind of a lot of boilerplate code here that you need to make this work well with typescript and we're going to show how we can get rid of some of that but let me just show basically how this works on the right here when I reload the page it dynamically fetches the new value of the stars for the next JS repository so the the value of the repo is forwarded to this component it's serialized here and then I'm able to use it inside of here so let's move this over to the app router I'll make a new folder we'll call this SSR and then I'm going to move this file into here yes we'll do page now I get a helpful message it says get server-side props is not supported inside of the app router but what I want now is to actually move to use the native async away data fetching inside of server components so let's take a look at what that would look like so instead of having this next.js specific typing what I can do is I'll just say well I'm going to have some asynchronous function we could even call it git server-side props if we wanted to you can keep this whatever you'd like and this is going to do basically the exact same thing I have a request to go get some information repo and instead of doing this props object that was required before I could just return repo directly here actually I can short circuit this a little bit and just return and implicitly do the await here so okay that looks right I don't need to do any of that that all seems good and then on side of on this function I want to Define what it's actually going to return so this is going to be a promise that has that's yeah a promise that has the repo so now inside of the page I don't have to do this forwarding of props here we can get rid of that so we export default function page and we're going to mark this as an asynchronous function and then inside of here we can do const repo equals await get server-side props or whatever you want to call that function and now we have access to the repo that we can use here so I can get rid of these Imports as well too basically we just got rid of a lot of custom code that was needed and this is typed for us so if I hover over repo here we see that it has the repo type and I get access to all the helpful editor commands as before so we reload the page and we see things now work as expected now this is really powerful because previously that was a client component inside of the pages router so we had to send additional JavaScript to the client even though this component is purely presentational there's no interactivity inside of this page but what if for example you did have interactivity inside of your page well you can still treat this model as basically an easier way or a better developer experience of writing the git server side props data loader as before so imagine that the UI here right imagine that we needed to have some kind of client component I'll just make a new file in here again you can co-locate components in the app router so we'll just call this client.tsx and we'll go back to here and let's just take this and actually what we're going to say is um well export default function client returned and we'll just put this in here and then we're going to forward the entire repo object inside of here now we'll ignore typescript for a second but okay we have this and then we want to do clients and then we forward a long repo as a prop so we get the repo here we hit save go back here reload and now if this actually had client side logic it would blow up because it would say hey you need to add the use client directive and we can add that but the pattern I really want to show here is this is basically what we were doing before there's this serialization of server to client where inside of here you know let's say add use client this is the kind of the same pattern as before I do some data loading and then I forward it to my client component I pre-render this UI from the server in the initial request and then inside of here I could then have some State like this if I wanted to and be able to use the existing ecosystem and all the different libraries of react components that I know and loved from before there's one last thing that we skipped over here with server rendering that's really important which is the result of a fetch is automatically cached for you inside of the app router which means that this is going to Cache to static by default so in reality this actually right now kind of works like a git static props this is only going to run once during the build so even though we're using server components these can still run during the build and be static but what if I did actually want to have this Behavior where this data was fresh on every request well now you can set this at the fetch level so for example if I go here and I add in some options I can add in this cache option that says no store now no store is equivalent to SSR fetch some new data on every single request and now I've effectively created the same thing as get server-side props but I have a lot more granularity because I can move it from the top page level down to the component or fetch level it's a similar story for ISR or incremental static regeneration as well too if I wanted this data to be cache static but then periodically update maybe at most let's say every 10 seconds I can add in this revalidate key here and I can pass it in some value and now I get the same behavior as using the revalidate key in get static props okay now the last piece on our incremental migration is actually the underscore app and document files now I saved these till last because you're still going to want these if you have some routes living in pages and some routes living in app these two things can co-exist and that's totally okay so you would probably wait to delete these until the end when you've migrated all of your routes Now app is basically a global layout for your application so we're not really doing anything special here except importing some Global Styles and document is allowing you to customize the initial response from the server so we're setting a language on the HTML we have a body here and we're kind of setting up the next JS boilerplate well both app and document no longer exist so we can delete these and you know what we're just going to delete this pages entirely and this has been replaced with the root layout inside of next JS so inside of here you have access to the raw HTML tag it's not an xgs specific API you have the body and then you forward in some children so you compose layouts by composing react components and forwarding their children and now that layouts are built into the app router you can have nested layouts inside of your application so you don't have to have just one Global layout with your underscore app file okay so we covered quite a bit pretty quickly but there's way more in this app router incremental adoption guide that we've published that walks you through how to upgrade to version 13 and not use the app router how to slowly move things over from pages to app and what the differences are between the pages apis and the app router API so I recommend giving this a read I'll put a link in the description as well too and that wraps it up for this video hopefully you found this helpful to see some practical examples of how you would move over routes from the pages router to the app router index.js thanks for watching and stay tuned for the next one peace
Info
Channel: Lee Robinson
Views: 36,242
Rating: undefined out of 5
Keywords:
Id: YQMSietiFm0
Channel Id: undefined
Length: 16min 21sec (981 seconds)
Published: Wed Jun 21 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.