Capítulo 342 de 456

Pages and Layouts

Core Idea

No Pages Router, cada arquivo em pages/ exportando um componente React é automaticamente uma rota; layouts compartilhados são construídos via composição de componentes (single shared layout via _app ou per-page layouts via getLayout).

Key Concepts

  • Page: componente React exportado de .js/.jsx/.ts/.tsx dentro de pages/, mapeado por nome de arquivo.
  • Index routes: pages/index.js/; pages/blog/index.js/blog.
  • Nested routes: pages/blog/first-post.js/blog/first-post; refletem a estrutura de pastas.
  • Layout Pattern: componente Layout reutilizado entre páginas (navbar/footer comuns).
  • Single Shared Layout: envolver <Component /> com <Layout> dentro de pages/_app.js; preserva estado do layout entre navegações.
  • Per-Page Layouts: propriedade Page.getLayout retorna o componente de layout específico daquela página, permitindo layouts aninhados diferentes por rota.
  • NextPageWithLayout: tipo TypeScript que estende NextPage com getLayout?: (page: ReactElement) => ReactNode.
  • Reconciliation: mecanismo do React que preserva estado da árvore de componentes entre transições de página quando a árvore se mantém.

Code Examples

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>
  )
}
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} />)
}
  • O que demonstra: padrão per-page layout, permitindo layouts aninhados distintos por rota sem perder estado em navegação.
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  const getLayout = Component.getLayout ?? ((page) => page)
  return getLayout(<Component {...pageProps} />)
}
  • O que demonstra: tipagem TypeScript correta para o padrão getLayout em _app.tsx.

Anti-patterns

  • Usar getStaticProps/getServerSideProps dentro do componente Layout: não é uma Page, então essas funções não têm efeito ali; buscar dados client-side (useEffect, SWR) dentro do layout.

Key Takeaways

  1. Roteamento é puramente file-system based: nome/caminho do arquivo define a URL.
  2. Existem dois padrões de layout: single shared (simples, um layout global via _app) e per-page (getLayout, para layouts distintos/aninhados).
  3. O padrão getLayout preserva estado de UI (inputs, scroll) entre navegações porque mantém a árvore de componentes React estável (reconciliation).
  4. Fetching de dados dentro de um Layout component só pode ser client-side.

Connects To

  • Dynamic Routes (ch343): extensão do sistema de rotas para segmentos dinâmicos.
  • Custom App (pages/_app.js): ponto central onde o padrão de layout global é aplicado.