Pages and Layouts in Nextjs- | Shalini Chauhan

Shared on React

editor-img
shared in

Pages and Layouts in Nextjs-

When building projects with Next.js, we typically create an entire user interface by assembling isolated components. However, some parts of the interface require the same code snippets across multiple routes — for example, the navigation header, footer, and sidebar. To manage this, we use layouts to structure the interface in a way that contains shared code snippets. Next.js recommends starting a new project with the App Router. However, we’ll discuss how to implement layouts and nested layouts with the Pages Router for users who have yet to migrate to the new Next.js routing system.

To help illustrate the differences between the two approaches, we’ll create the same application using both methods and compare how the new App Router simplifies the process of implementing nested layouts.

To start, let’s take a look at a typical folder structure for the Pages Router in Next.js:

...

├── components

│ ├── Footer.js

│ └── Header.js

├── pages

│ ├── dashboard

│ │ ├── account.js

│ │ ├── analytics.js

│ │ └── settings.js

│ ...

│ ├── index.js

│ └── newsletter.js

...

To define a layout with the Pages routing system, we create a Layout component that renders any shared user interface and its children.

Create a components/Layout.js file and render the shared header and footer content:

import Header from './Header';

import Footer from './Footer';

const RootLayout = ({ children }) => {

return (

<>

<Header />

<main>{children}</main>

<Footer />

</>

);

};

export default RootLayout;

The Layout component takes a children prop that serves as a placeholder for the active page content.

const RootLayout = ({ children }) => {

return (

<div className="flex flex-col min-h-screen mx-auto max-w-2xl px-4 pt-8 pb-16">

<div className="flex-grow">

<Header />

<main className="my-0 py-16">{children}</main>

</div>

<Footer />

</div>

);

};

However, this implementation doesn’t preserve the state between page transitions. For example, the search field’s input text gets cleared when navigating between pages that share a common layout. This isn’t the experience we expect from a single-page application.

Persisting layouts in the Next.js Pages Router

If we examine the pages/_app.js file that Next.js calls during each page initialization, we’ll see an App component that includes a Component prop representing the active page:

import '@/styles/globals.css'

export default function App({ Component, pageProps }) {

return <Component {...pageProps} />

}

In this file, we can load the shared layout and other global files, such as the global CSS file. So, let’s wrap the page content with the <RootLayout> like so:

import '@/styles/globals.css';

import RootLayout from '@/components/Layout';

export default function App({ Component, pageProps }) {

return (

<RootLayout>

<Component {...pageProps} />

</RootLayout>

);

}

With this implementation, the RootLayout component is reused between page transitions. As a result, the state in the shared component, such as the Header, will be preserved.

We no longer need to wrap each page’s render with the <RootLayout> component.

After saving all files and revisiting the application, we can write in the search field and see that the state now persists between page changes, which is an improvement!

Creating nested layouts with the Next.js Pages Router

To create a nested shared layout, as demonstrated in the /dashboard/* pages, we need to nest a new layout that renders the sidebar navigation within the root layout.

However, with the current implementation, simply wrapping the active route within the root layout — as we did in the pages/_app.js file — only works if we require one layout for the entire application.