ymc9
Posted on December 1, 2022
Next.js 13 has landed in a somewhat confusing way. Many remarkable things have been added; however, a good part is still Beta. Nevertheless, the Beta features give us important signals on how the future of Next.js will be shaped, so there are good reasons to keep a close eye on them, even if you're going to wait to adopt them.
This article is part of a series of experiences about the Beta features. Let's explore the new routing system today.
Next.js 13 introduced a brand new app
folder with a completely renovated routing system. It includes many improvements, and among all, the best gift is the new layout mechanism.
The app
folder can coexist with the old pages
folder as long as their routes don't clash, which allows you to adopt progressively. This post will cover the most notable new stuff with the app
folder.
New folder structure
The app
folder makes defining routes more explicit by requiring every route to be a folder. A route folder typically contains the following route files (with .js|.ts|.jsx|.tsx
suffix):
- page
Provides UI specific for this route.
- layout
Provides layout UI for this route and all descendant routes.
- loading
Provides a loading UI when server components for the route are being loaded - more on this in the next section.
- error
Provides UI for dealing with errors within and under this route (unless handled by another error
route in a descendant layer).
For more information about server components, check out the post below:
Fun With Next.js 13 Server Components
ymc9 for ZenStack ・ Nov 25 '22
Layout and nesting
The renovated folder structure sets a good foundation for introducing more convention-based route files. As a result, it's now much easier to create, share and nest layouts in Next.js than ever.
Let's see what got changed.
In previous versions
Before Next.js 13, the officially recommended approach for creating a nested layout is for each Page
to "declare" its layout, compose nesting, and then apply them at the top level in pages/_app
.
// pages/index.js
export default function Page() {
return (
/** Your content */
)
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Although this approach results in optimal performance (because layouts are not remounted when changing route), it's cumbersome and unnatural, especially compared to what react-router offers.
With Next.js 13
The new routing system makes "layout" a first-class citizen. At any level of folders under app
(i.e., any level of routing), you can use a layout.tsx
to explicitly define a container component. This container component will automatically wrap around all pages in and under that folder. If there're multiple layout.tsx
components at different levels, a wrapping hierarchy is automatically constructed:
Much more straightforward than the old getLayout
hack, isn't it?
A "grouping" feature is also available for you to create "logical" groups of pages to share the same layout without introducing an extra routing layer:
As you can see, although /about
and /blog
don't share the same route prefix, they can share the same layout by residing in the same route group. Who doesn't like a bit more flexibility 👻?
Other notes
-
Passing data from layout to children
You can't do this. But it is not as serious a problem as it may seem because the new data fetching mechanism in Next.js 13 has built-in dedupe and caching, so it doesn't harm to fetch data in layout and its children components repeatedly.
I'll cover the new data-fetching system in a future post. -
Breaking out of layout hierarchy
There isn't a way for a page to "escape" the layout ancestors in the routing hierarchy. You'll have to design your routes or route groups carefully. In comparison, SvelteKit does provide better flexibility on this.
Error handling
Error handling is a small but convenient feature. The idea is quite simple:
- React has an Error Boundaries concept for capturing errors in a structured way.
- Next.js's route folders naturally form a component hierarchy.
- Why don't we invent a convention to handle errors at any level of routing?
That's what the error.tsx
file does. It's nothing but syntactic sugar for wrapping the descendent component tree within a <ErrorBoundary />
:
With that, errors are localized to parts of UI rendered by sub-routes without affecting the display and interactivity of any other parts.
In the End
Thank you for your time reading to the end ❤️.
This is the second article of a series about the Beta features of Next.js 13. You can find the entire series here. If you like our posts, remember to follow us for updates at the first opportunity.
P.S. We're building ZenStack — a toolkit for developing secure CRUD apps with Next.js + Typescript. Our goal is to let you save time writing boilerplate code and focus on building what matters — the user experience.
Posted on December 1, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.