Sam Selikoff: Improving developer and user experience with nested layouts in Next.js

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign [Music] hi there my name is Sam selikoff and I'm super excited to be talking to you about one of my favorite features coming to next 13 nested layouts I've used nested layouts in a lot of different Frameworks going back to my time in Ember and I love the power they give you to build uis for the web and today we're going to see exactly how they work in next 13 by looking at this demo app so this is a brand new Next 13 app we're going to see we have this root app folder with two files layout.js and page.js and here is the root layout so the first thing you'll notice about this layout is that it renders the HTML head and body tag so it's actually rendering the entire document and the second thing you'll notice is this children prop which it's slotting in right here inside of the body tag and that's what's rendering our page component so uh right now we have one page right at the root URL let's go ahead and make a second page with movies hey hjs and we'll export a default function and let's return a tag that says the movies page so now if we come over and visit movies look at that we've got a new URL in our app so this is how we create pages in next 13. and if we come back to the layout let's come within our body tag and we'll add a header right here and now if we look at the movies page or the home page we're going to see that header text on both pages so in next 13 layouts are a first class concept we can see here the header is being rendered above both pages right above this children right here so this makes layouts a great place for persistent nav like some links so let's go ahead and add a nav tag we'll add a home link and we'll add a link to slash movies and now we can see both of these links are showing up and when we click them we can see the pages being rendered now just like in next 12 we have a special component called link so let's go ahead and change these to use that and now when we click these we're getting nice client-side Transitions and some other Behavior like pre-fetching that we already know and love from next 12. so as you can see this layout is the perfect place for our header and it's also a great place to do some Global stuff like importing Tailwind CSS which we can do right up here we can see that taking effect and adding some Global Styles like BG gray 900 let's make this a dark app and we'll add text Gray 100 for the text and let's just throw anti-aliased right here and now we can come down and add some space between these links maybe add a bottom border to our header with some padding and we'll also add one more div around kind of the main panel of our layout here so we're off to a good start but it'd be nice to know which one of these links are active when we actually click on them maybe we could toggle some classes on this link tag well uh next 13 has a great hook that lets us do just that it's called use selected layout segment from next navigation here and uh if we go ahead and save this we're actually going to see an error and if we come over and open the docs for you selected layout segment we're going to see that this is a hook that allows us to read the current route segment inside of a client component and so it turns out this whole time we've actually been working with react server components they are the default component type in next 13. and if I go ahead and comment this out and drop a console log for rendering and we come back and refresh our app you might be surprised to see that this doesn't show up here and in fact if we pop open our terminal which is running our Dev server we see that console log right there so our next Dev server is actually rendering these server components at request time on the server and then sending their output up to the client and this is different from how server rendering Works in next today which is pre-rendering client components sending up the HTML but then also setting up all the JavaScript so those client components can be rehydrated on the client and then they start running and executing there server components don't do that they just run on the server and they just send their static output up to the browser and this helps keep the static parts of our app really fast and it helps us send less JavaScript to the front end as well but when we do want the full power of react on the client and uh want to be able to add some interactivity like we do right here to be able to tell which link is active we want to opt into using a client component and so the way we're going to do that is by making ourselves a brand new component let's call it navlink.js and nav link is going to be rendered right here so we will export default function nav link and we want to return a link from next.js and we want to go ahead and take the href and children as props just like that so now if we import this and get rid of these let's save this come to our nav link and say log href so in next 13 we can make new components anywhere we don't have to put them in a components directory but if we refresh this we're still going to see actually all these logs happening on the server and that's because any component under app is a server component by default but we can turn this into a client component with use client and check this out now when I save this and we refresh we see The pre-rendering Happening Here we see our server component rendering but we're also seeing these components being rendered on the client and that's exactly what we need to be able to use selected layout segment so uh let's grab this segment from this and let's go ahead and log these two and uh we'll refresh right here on the home page and we'll see that the the selected segment for the home page is just the empty string for slash movies it's movies so we should be able to see if these are active if the href that we pass in is equal to our segment with a slash in front of it so now if we log href and active and uh now we'll see when we're on the home page active is true for that ahref and when we click movies uh active is true for this one so now we can just come here and do good old react things like setting a conditional class name of underline if we're active and check that out pretty cool right so we have this nav link component which is using react on the client to toggle this class name but it's being rendered by our layout which is still rendering on the server it's still a react server component and this interleaving of server and client components is really a key part of next 13's architecture it gives us the full power of react whenever we need it and only at the component level but it keeps the static parts of our app rendering on the server and I just love how seamless it is to move between the two okay uh let's fetch some data we have this movies route and we actually want to display some movies here and over on localhost 3001 I have an API running with a few movies so uh let's come to our movies page and fetch those movies and we're going to do that using an async function that we're going to call get movies so uh let's go ahead and await fetch to that API endpoint and let's return response.json and to get this data into our component we are going to import something called experimental use from react and we're going to give it an alias of use now you might have heard of suspense for data fetching and how it hasn't been ready for a while well this is it and let me show you how it works I come right into our component and we're going to call use and we're going to pass it our get movies function which we'll go ahead and invoke so uh this returns a promise and we're just going to assign this to a variable called movies and let's go ahead and log movies right here and if I pop open our terminal we're going to see our movies are logged right here so we can go ahead create a list and movies.map each movie to An Li with a key of movie ID and let's go ahead and render the title of each movie and there we go now we see the movies uh in our app so uh this is really cool and it's really the first time that react has given us a first class API uh to fetch data within a component and basically a way to tell other components that this component is currently fetching data via suspense and that's how this is all working in fact if we go to the home page and we open up the dev tools and slow this down to a slow 3G throttle uh if I click on movies we're actually going to see that the app pauses and it doesn't navigate until all the data is ready and again react has never been able to do this on its own it's always needed a framework to provide a framework specific hook like get server side props to have this kind of traditional request response Behavior but uh now through the power of use and suspense pages are able to communicate that they're fetching data and they're not ready to be rendered so having this as part of react is going to really improve the composability story across different libraries and Frameworks because every framework no longer has to come up with its own apis for fetching data and doing things like rendering loading and error States and speaking of loading States it was a little weird how when we clicked on this on slow 3G it took a while for it to load so let's go back online come here and we can fix that if we come here and right next to this layout we drop in a loading.js and let's go ahead and Export a loading component and just return loading message right here so now if I go back home and we refresh and go back down to slow 3G let's click on movies and look at that we see an instant loading template that renders while our data is being fetched so uh this is pretty awesome we basically have this way to go between the pattern where we instantly navigate and show a loading spinner or we do kind of the traditional model where we click a link we wait for the data to be fetched and then we render the new page and we can do either one of those approaches to navigation without changing anything about how our page fetches data thanks to use and thanks to suspense okay now we're ready to actually uh make these movies link somewhere so uh we want to come here add a div and uh let's kind of make a flex style layout where we have the movie detail kind of right here to the right so let's go ahead and add some padding right to this maybe we'll make the text small and now we want these movies to actually link to you know slash movie slash one slash movie slash two where we can see some more information about the movie and this looks a lot like another layout where our movies are kind of in the sidebar and the detail is here in this main pane which gets swapped out so uh let's go ahead and turn this page directly into a layout just by renaming it to layout and uh layouts get a children prop which we can render right here to this div so if we save this and refresh we're going to see a 404 because we're trying to render slash movies and we no longer have a page defined so let's go ahead and create a page to be slotted in to that children's slot we'll say page return movie page and uh now we can see that right here so this page is kind of the index segment the default segment for movies so maybe we make it say something like select a film and uh now we want to make these uh movies right here in the layout links so we'll wrap these in link which we can import from next link and we want the href to be slash movies slash movie ID so now we come and look we see that uh this is going to slash movies slash one and uh this is movie slash two we don't have Pages for these yet but because the URL has a dynamic uh parameter here this is the perfect use case for a route with a dynamic segment and we can create a dynamic segment with brackets just like in next 12. so we'll call this bracket ID and then we'll drop in a new page here which is going to be a component as well movie detail so uh now we have this page being rendered but we want to know which movies being rendered Pages under Dynamic segments here will get the params in right as a prop so if we log in prams there we see id2 id1 and so we can say movie params.id just like that and let's go ahead and make this text 3XL so uh look at that pretty cool we've got our home route we've got our movies route and uh this kind of renders the index and now we can render these movies and this is kind of our first level of nesting going on here where we have this root layout and then we have this nested layout keeps things really nice and tidy and only re-renders the portions of our page that change now for this detail page we actually want to fetch the details of each movie so uh let's come and grab our async function from our layout and we're going to turn this into a data fetching page but this time we're just going to grab a single movie which we can do by hitting movies slash ID just like this so if I come over to my API and go to slash one there we'll see Lord of the Rings so we'll make our async function take in an ID and then let's come and grab experimental use and uh we'll get the movie by using get movie which takes in an ID and we can get this right from params so let's go ahead and log the movie there we see Lord of the Rings and there we see Star Wars so let's use this data right here and render the movie title pretty cool Lord of the Rings and Star Wars let's add one more wrapping div paste in uh the year and description and let's come back to our layout and we'll add flex and none to this unordered list so that it doesn't shrink here and uh look at this pretty cool little nested UI we have we can go home we can go back and uh if we take a look at what we've built each layout and page is kind of isolated right we've got our detail page here which is fetching data and rendering it our layout is fetching data and rendering it and then we have this root layout right here so the nesting that's going on here kind of starts on the outside with the root layout that renders a segment right here and then we have another layout here that renders the sidebar and then the current segment right here and everything is kind of nice and tidy all the pieces that are coupled together are in the same file so we don't have to go to the top of a route and make sure we fetch all the data for every component that needs it we can just look at this kind of leaf page right here in our system see that it needs a movie and it can fetch it right here and it can use it right in the component so from a DX perspective this is awesome because uh it really keeps things nice and coupled together the things that are related to each other and uh not only is having these fetch calls associated with the components that need them good for DX it actually opens the door for a lot of optimizations on both the react and the next JS side if we have more fetch calls associated with each dynamic segment of our UI they're easier to Cache across different pages also having the fetch calls near the components that need them will prevent over fetching because if you have to Marshal all the data that you might ever need it becomes easy to over fetch data and finally next we'll deduplicate and parallelize these fetch requests so we don't have to worry about fetching too many times or too much data even though they're co-located with these Dynamic segments so overall this is pretty awesome from both a DX and a ux perspective but you might be wondering with all these calls to fetch have we lost some of the coolest features of next things like get static props and incremental static regeneration let's take a quick look at what happens when we build our app I'm going to come down here and this terminal that's running my API server I'll kill that so that I can run it kind of split right here and PM run API and let's just clear this and here's our next Dev server I'll kill that and let's run npm run build now uh look at that we're going to see our API server was hit during our build and up here it said we're collecting page data and generating some static Pages now let's go ahead and npm run start which will start our app in production and uh we'll clear our API server again and let's refresh our app so uh we actually don't see our API server getting hit at all and this is because uh next was able to detect that these pages are static and by default it is actually caching the fetch requests that we're making right here so this is basically the equivalent of get static props now once we click on these links we're going to see the API request going out to the movies and this is because these pages are using a dynamic param and next at build time doesn't know which Pages it should pre-build so you might know from next 12 we have this API called get static paths which we can use to tell next to pre-build certain pages well in next 13 we can come to the page under our Dynamic segment and we can export a function called generate static params and here we're going to fetch all of our movies and we'll await that and then we can await response Json which is going to give us an array of movies and now all we have to do is return an array of objects with a key of ID to match the dynamic param so let's return movies.map and for each movie we will return an object with the ID now let's come back to our terminal go ahead and clear our API server and we'll run build again and look at that we see a lot more API endpoints being hit we see we have six static pages so now if we run npm run start and we go ahead and clear this we can refresh and look at that everything's instant we're not even depending on the API server at runtime so we can see that next capabilities for static rendering aren't going anywhere it's just that we no longer have to use any proprietary apis like get static props we still get to fetch data the exact same way in every page in every layout on the server using use and the power of suspense now of course these fetch calls can be configured to make requests at runtime that's a bit beyond the scope of this talk but uh I hope that got you excited for next 13 and all the cool stuff that comes along with nested layouts I can't wait to start building apps like this I've already had so much fun and it's really just the beginning so I hope you enjoyed that talk enjoy the rest of the conference and have a great day
Info
Channel: Vercel
Views: 48,113
Rating: undefined out of 5
Keywords:
Id: 6mQ3M1CUGnk
Channel Id: undefined
Length: 23min 12sec (1392 seconds)
Published: Wed Oct 26 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.