Pages and Layouts in Next.js
Enhancing Next.js Applications: Harnessing the Power of Pages and Layouts
Next.js offers a powerful file-system based routing system that makes it easy to create dynamic and nested routes. Additionally, you can create reusable layouts to structure your pages consistently across your application.
Pages Router in Next.js
The Pages Router in Next.js is based on the concept of pages, where each page is a React component exported from a .js
, .jsx
, .ts
, or .tsx
file in the pages
directory. When a file is added to the pages
directory, it's automatically available as a route. Here's an example:
export default function AboutPage() {
return <div>AboutPage</div>
}
In the above example, the About
component will be accessible at /about
.
Index Routes
Next.js automatically routes files named index
to the root of the directory. For example:
pages/index.js
→/
pages/blog/index.js
→/blog
Nested Routes
Next.js supports nested files, where files in nested folders are routed accordingly. For example:
pages/blog/first-post.js
→/blog/first-post
pages/dashboard/settings/username.js
→/dashboard/settings/username
Pages with Dynamic Routes
Next.js supports pages with dynamic routes using brackets []
. For example, pages/posts/[id].js
will be accessible at posts/1
, posts/2
, etc.
Layout Pattern
You can deconstruct a page into a series of components in Next.js, allowing for reusable layouts. For example, you might have the same navigation bar and footer on every page. Here's an example layout component:
// components/layout.js
import Navbar from './navbar';
import Footer from './footer';
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
);
}
Single Shared Layout with Custom App
If you have one layout for your entire application, you can create a custom app and wrap your application with the layout. This preserves component state when changing pages:
// pages/_app.js
import Layout from '../components/layout';
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
Per-Page Layouts
If you need multiple layouts, you can define the layout on a per-page basis by adding a getLayout
property to your page. This allows for complex nested layouts:
// pages/index.js
import Layout from '../components/layout';
import NestedLayout from '../components/nested-layout';
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} />)
}
Data Fetching in Layouts
Inside your layout, you can fetch data on the client-side using useEffect
or a library like SWR. However, because the layout file is not a page, you cannot use getStaticProps
or getServerSideProps
currently.
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
const { data, error } = useSWR('/api/navigation', fetcher)
if (error) return <div>Failed</div>
if (!data) return <div>Loading...</div>
return (
<>
<Navbar links={data.links} />
<main>{children}</main>
<Footer />
</>
)
}