In Next.js, you can use the Layout component pattern by adding the getLayout
property to the pages. This property is a function that returns a React component. The Layout component can be used to add common UI elements to all pages, such as navigation or footer.
Not only this pattern avoids duplicate code, but it can also persist state between page navigations. It's a great way to add a Single-Page Application (SPA) experience to your Next.js application.
You can find more details about this pattern in the Next.js documentation. But, the first time I saw this pattern was from Adam Wathan's blog post about Persistent Layout Patterns in Next.js. He really gives a great explanation of this pattern and how to use it.
The Layout component pattern is extremely useful when some parts of the UI elements are exactly the same. For example, the footer of the website: between each page, the footer doesn't change at all.
So, you can easily create a function that returns the footer. Then, you can use it as the Layout component in all Next.js pages. Here is a simple example of a Layout component that returns a footer:
const getFooter = (page: ReactElement) => (
<Footer>{page}</Footer>
);
In Next.js pages, you can use this function as the Layout component:
// pages/index.js
export default function Page() {
return {
/** Your content */
}
}
Page.getLayout = getFooter;
But for more complex applications, like the user/admin dashboard, the common UI elements can be slightly different between pages. I would love to add a title to the header, and for each page the title is different. Here is an example:
And, the only difference between the pages is the title. The rest of the UI elements are the same. So, how can I reuse the Layout component and still be able to change the title? You can create a new function for each different title, but it's not a good solution. Here is a potential example:
const getDashboardChangeEmail = (page: ReactElement) => (
<AuthProvider>
<StateProvider>
<Dashboard title="Change Email">{page}</Dashboard>
</StateProvider>
</AuthProvider>
);
const getDashboardChangePassword = (page: ReactElement) => (
<AuthProvider>
<StateProvider>
<Dashboard title="Change password">{page}</Dashboard>
</StateProvider>
</AuthProvider>
);
You have to create a new function for each different title. You have a lot of duplicate code and it's hard to maintain. And, if you want to add a new component, you need to update all of them.
Instead of duplicating code for each title, you can curry the function. Now, you can create a function that takes the title
as a parameter and return a function. And the second function will return the React component:
const getDashboard = (title: title) => (page: ReactElement) => (
<AuthProvider>
<StateProvider>
<Dashboard title={title}>{page}</Dashboard>
</StateProvider>
</AuthProvider>
);
And, here is how you can use it on Next.js pages:
// pages/change-email.js
export default function Page() {
return {
/** Your content */
}
}
Page.getLayout = getDashboard('Change Email');
// pages/change-password.js
export default function Page() {
return {
/** Your content */
}
}
Page.getLayout = getDashboard('Change Password');
Now, we can reuse the same Layout component for all pages. And, we can still change the title for each page. The code isn't duplicated anymore. It also doesn't require a lot of changes to the existing code.
I'm totally open to any feedback or suggestions, please feel free to contact me on Twitter at @ixartz.