Introduction to Next.js 13+, v3

Layouts & Templates

Scott Moss

Scott Moss

Superfilter AI
Introduction to Next.js 13+, v3

Check out a free preview of the full Introduction to Next.js 13+, v3 course

The "Layouts & Templates" Lesson is part of the full, Introduction to Next.js 13+, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott demonstrates the usage of layout components to share common UI elements across different pages. Templates, similar to layouts, are used to render components every time a route changes.


Transcript from the "Layouts & Templates" Lesson

>> So let's get to layouts and templates and let's write some code. So we've seen layouts. You heard me talk about layouts. Let's just get into it. So right now, let's go take a look at the layout TSX that we have here and the app that was generated for us.

And if you've ever used the earlier version of Next.js, you've probably are asking so where does the like. Where does the app file go? Where like I write the app template, if I wanna do something globally for the entire app, where's the root app basically? Well, layouts kinda served that purpose.

So a layout, like I said earlier, is just a component that wraps other layouts and other pages, right? It's like, I have some common functionality, typically UI, sometimes data that I want for every single route underneath this layout. So I'm just going to create a component that does this.

In fact, this was such a highly requested feature. If you go back and look at the older version of Next.js and you find that the part where they talk about layouts. They basically say, well, here's how you do it yourself because we don't support it. And it's never a really good solution.

It's just like, they're all just trade-offs. Now they figured it out, how to do that. The other biggest complaint was in the older versions of Next.js, you could only do data fetching in pages. But if you need to do data fetching in a layout, let's say your layout was, navigation on the left, navigation on top, and on the top, you had to show the user's avatar.

So you had to do some type of fetching to get the user's information here. But if that was in a layout, you couldn't do it on the service side because layouts couldn't do data fetching. So it was like you had to do all this weird work around in order to get this to work.

But now that's not the case, data layouts are treated just like pages. They are first class citizens, they can do data fetching, and they allow you to share UI. So, one rule you have to have in Next.js app router is that you have to have a root layout.

But there's many ways you can do it. One way you can do it is the way that we see here. As in there is a layout file immediately in the root of the app file, and this is the root layout. This is like the app.js or JSX or TSX that you had in the previous version of Next.js.

It's where your whole app gets rendered into, so you kinda need this. You can see I'm actually using the HTML tag here and the body and then everywhere where you see children, that's where the pages get rendered, right? So the pages get rendered here. This is also a great place to do anything global, like I have some global CSS, some font stuff going on here.

Don't worry about this metadata thing. We will talk about that, but essentially it's just a function. It's just a component that can do whatever it wants and it renders its children which are gonna be pages. That's it.
>> This is a case where root layout is a specially namespaced magic keyword or it could be export default function foobar.

>> Yeah, so this name is irrelevant. You can call this whatever you want. Yeah, this is just what they generated with when we did that. Create next app, but yeah, there is no convention around the name of a component in Next.js, you can call it whatever you want.

I just prefer to keep it capital. But yeah, this name doesn't mean anything. You can call this literally anything. But it is a layout. You can see that we got some CSS here. We got our classes. We're wrapping our children. And as far as like the children, where does this come from?

Well, if you look at layout, are there any routes that are children of this layout as in are there any folders that are next to it? Yeah, so that means everything in docs, everything in dashboard is gonna be rendered here and any pages next to it. So this includes this page here, right?

And just to illustrate that, I can just move this down a little bit and I can just say, layouts like this, right? And then I can put the children here. So once I put layout there and I go back to our app, there's always gonna be layout, right?

That's huge. There's layout right there. It's always gonna be here cuz it's part of the entire app. It's always here. The other sweet thing about layout is that even though the route changes, the layout never re-renders. It is cached. It doesn't re-render or re-evaluate. When you change the route, it stays the same, which is so great for something like a UI.

And if you had to do some of this on your own or previous version of Next, trying to make sure that doesn't re-render was always a pain, like you had to do memos and using it. It was always a pain to try to do that stuff yourself. So now it doesn't.

Layouts just don't re-render. They will always stay on the page no matter what route you go to, which is pretty useful. And then you can have nested layouts, right? So back to our route grouping, example, if I wanted my dashboard to have a specific layout to it that my landing page wouldn't have, I would add that here, right?

So in this case, I do. My dashboard is probably gonna look different than my landing page would. So I'm gonna add a new layout here in the dashboard group folder. So I'm gonna make a new file and I'm gonna call it layout.tsx, yes?
>> Could you fetch user info in the route layout?

>> Yeah, you could fetch user info on the route layout. You could totally do that. We'll get to data fetching in a minute, but yeah, you can fetch data and any, Any component, any server component at this point. I mean, you can also fetch any client component, but that's not anything you need to Next.js such as React.

But yeah, you can fetch data pretty much anywhere. The only caveat though is that you can't pass data down from a layout to its children through props. You can't do that. So, although you can't fetch data, you cannot pass it down. And that has a lot to do with the fact that, one, the layouts don't get re-rendered, so if the data changed, it's not re-rendering it back to the children.

So it would only work the first rendered and anytime after that, it'd be stale, so you wouldn't wanna use it, so that's how they keep that. That way, it also has something to do with how crossing the network threshold of client and server and what can and cannot be serialized over the network.

For instance, you can't serialize a function over the network. So passing a callback as a prop is, you can't do it because you can't send a function over the Internet but you can send data. So we'll talk about that when we get to client components, but it's a lot of limitations there.

Cool, so back here in the dashboard group, I have layout, I can make a new dashboard layout Right and it's just a function that we do, that we export. And the only thing about layouts, you can do whatever you want. You just need to make sure you render the children.

Because if you don't render the children, they'll never show through. It'll just only show your layout. So just be sure to do that. So you always wanna make sure you have your children prop, return your div. I'm gonna put an h1 here that says dashboard And if it has my children, like that.

So I have my dashboard layout. Now, any children here should be anything that's sibling to this layout, which I don't have. Anything that's a child of it, which in case it is this todos. So if I go to slash todos, I should see this dashboard load up as well.

So let's try that. There we go. So you can see here's the route layout, which nests the dashboard layout, which renders this page, So that's how we're able to nest layouts, because they just reside in folders underneath each other. Now, let's say our dashboard and our homepage were so significantly different that I don't want them sharing layouts, period.

Right now, they do. Right now, they both share the root layout, but let's say they're so different that I don't even want that, but I need a root layout. Anyone wanna guess how you might do that in this file system?
>> Tell me it's not putting app in paren.

>> Close [LAUGH] we do need more parens, but it's not putting app in parens. It's basically getting rid of the root layout and making another group, maybe call it like marketing site or something like that, and then putting that in parens and putting its own layout in there.

That way there is never a layout on the root of the app. The only caveat with that is that, let's say you had ten route groups on your app. One of those route groups has to have a page on its root. So when someone goes to slash, it renders, right?

So that is the only caveat. So this isn't part of the app, but I'll show you. So I'll make it, so if I say folder and I say, yeah, cool, this is marketing, right? Now marketing has its own layout. Then also when someone goes to /, I want to load up this route right here.

So I put that here on the route and then any other folders that I put here what it's the about page. It's the blog, right? I can put all that in marketing. And then I could just get rid of this layout, right? I can just delete this file.

If that makes sense. And that's actually typically how I build sites now Next.js. Actually just do grouping like this. I'll just have like my app and like dashboard or whatever, I have the landing page and like marketing, I might have something else over here, admin or something like that and they're all just their own groups with their own layouts but it's in the same repo.

That's if you put it all on one domain. You might just separate all this on different websites and different domains, but this is just like if you need a one domain, you just do it all here
>> Did I understand correctly that having a layout file in every route group, you will not work if there are dears that are not route group?

>> Say that again.
>> So like in this case, we lay out TSX because the docs directory does not have a layout file in it.
>> Got you. Okay, I see. Yes, so the docs directory would need a layout cuz it's like, where's my layout? It wouldn't work.

It would need a layout. So yeah, if you don't have a layout on the root, then every folder whether it's actual segment or group segment has to have a layout on its route, because every page has to render in a layout. Cool, yes.
>> What's the best way to separate routing for the marketing part of the site versus the app part of site?

>> It comes down to whether or not you care about the URL being changed. So if you want the URL to reflect those differences, then just get rid of these parentheses, and then you would just have, I would say by default, have the marketing just be folders on the route of the app.

And then have the app be grouped into something like dashboard or slash app, and then you can put your whole app in there, and that's just separating them functionally, but they were still share the same route layout. Now, if you want them to be completely separated, as in like they're almost basically two different completely apps, they don't know about each other's routes.

They don't have the same route layout. Then you would do what I'm doing now. You would put two route groups, one that represents the app that someone logs into, one that represents the marketing website. If you put a layout on both of them like I have now and yeah that's it.

Now they're separated and you just need to make sure that on your route of your marketing, you have a page here. So when someone goes to your website, the route of it loads this page, otherwise it wouldn't know where to go. And then from dashboard, you don't have a page here because as I showed you earlier, those will resolve to the same conflict.

They both would just be slash. So it's like, well, which one are you showing? Are you showing dashboard? Are you showing marketing? So in dashboard, you would just have settings, whatever routes you have for your dashboard you put them in here, and that's exactly what I do. This is literally how I make apps now.

So again, route grouping is the best reason for route grouping, is that I just want to opt all these routes into this layout. That's it. And I don't want to change the URL. If you do wanna change the URL, just get rid of the parentheses. Like we did with docs.

Docs has parenthesis on it cuz I do want it to say slash docs. But I don't wanna see slash dashboard in my URL. That's gross to me. I don't like it, yeah.
>> So if you put it on a subdomain, would you host a different app then?
>> Yeah, I mean, if it's on a subdomain, you might as well just host a different app.

I guess you could write some DevOps logic yourself to deploy us. I mean, I guess you can get away with this by just doing some smart rerouting on the Edge too. There's a lot of ways to do it. With today's world, with edge computing, I guess you could just write a function on the edge that takes a specific path from this app and routes it or take some specific path and route it to the URL on this app that will be treated like a subdomain.

But historically speaking, most people do is like it's a different app. [INAUDIBLE] different app that gets deployed to a different subdomain and you just go change the CNAME and whatever hosting provider that you have, and pointing to that subdomain in the DNS. So yeah, probably I wouldn`t do it the other way because it sounds like a lot of work.

But I guess if you're trying to save money, I guess if you want to save $0.20 a year, you could do that. Cool, any other questions?
>> So does the same folder in different groups collide?
>> Does the same folder in different groups collide? Let me see if I understand that question.

So I think what they're saying is if I have todos in dashboard and then I have todos in marketing. Do they collide? Absolutely, they do collide. Those are the same route segments. So and we saw what happened when we make the two, Next.js seems to pick the one that comes after.

Or maybe they'll be smarter to throw an error, but yeah, you definitely won't get the behavior that you want. So you need to know what are in the other folders when you're making other folders with route groups. With this one I don't have to care because I know we're protected because it's always going to be slash doc.

So I can put todos in here and it will still work because there's nothing else in here that is slash doc, slash todos, so I'm totally fine. But with these, I do need to be aware of what is an other one because these segments don't exist. It's just our website slash todos, our website slash about, our website slash blog.

So I have to be aware when we do route group and you haven't known what other groups have. So now what we want to do is just briefly talk about templates and then we'll set up some navigation to get our app navigation working with the layouts and things like that.

So templates, very short, it's literally the same thing as layouts, except they do re-render across routes. That's it. That's literally it. And you can make a template just by making a template.tsx. You will almost never use it, and I think they just added it back to the documentation like a week ago.

They kept removing it and adding it, because people were just getting confused by it. Also I think the naming is weird, because I feel like layouts could be templates, but really the only use case I've found for templates, there's only two use cases. One, animations. I want something to animate in and animate out as the route changes like a layout.

And if it's not re-rendering then it will never leave and enter. So a layout will never show that animation, but a template would because it leaves and enters on every route change. So if you want a route animation, use a template. The other use case would be something around, you had your template be a client-side component as in it is a regular React component you've ever made your entire life.

And you have something in the use effect that gets kicked off when the component renders. And you need that to happen every time that component renders, well, if it's a layout, it will never re-render, so it's only gonna do that once ever. But if you're thinking that it's gonna happen every time someone changes the route and that's what you're expecting to happen, then you would need to switch to a template.

So it does re-render and kick off your use effect every single time. But then I would argue like why are you doing that? Like she probably do something else somewhere else. But if you absolutely needed it, then yeah, other than that you'd use the layout I think [INAUDIBLE] was just because they could, why not, but I don't think you'll almost never use those.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now