Capítulo 4 de 456

Layouts and Pages

Core Idea

Como criar páginas e layouts com roteamento baseado em arquivos, aninhar layouts, criar rotas dinâmicas, ler search params e linkar entre páginas usando <Link>.

Key Concepts

  • page: UI renderizada em uma rota específica; default export de componente React dentro de app.
  • layout: UI compartilhada entre múltiplas páginas; recebe children, preserva estado e não re-renderiza na navegação.
  • Root layout: layout na raiz de app, obrigatório, precisa conter <html> e <body>.
  • Nested routes: pastas aninhadas mapeiam segmentos de URL (/blog/[slug] = root + blog + [slug]); layouts se aninham automaticamente na mesma hierarquia.
  • Dynamic segment [segmentName]: gera rotas a partir de dados; acessado via params (que é uma Promise a ser aguardada com await).
  • searchParams (prop de page): acessa query params em Server Component; opta a página em dynamic rendering porque precisa de uma request de entrada.
  • useSearchParams: hook para ler search params em Client Components, sem opt-in em dynamic rendering quando a página já está prerenderizada.
  • <Link>: componente que estende <a> com prefetch e navegação client-side.
  • PageProps<'/rota'> / LayoutProps<'/rota'>: helpers de tipo globais (gerados por next dev/next build/next typegen) que inferem params, searchParams e slots nomeados sem necessidade de import.

Code Examples

// app/blog/[slug]/page.tsx
export default async function BlogPostPage({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const post = await getPost(slug)

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  )
}
  • O que demonstra: leitura de dynamic segment via params assíncrono.
// app/blog/[slug]/page.tsx
export default async function Page(props: PageProps<'/blog/[slug]'>) {
  const { slug } = await props.params
  return <h1>Blog post: {slug}</h1>
}
  • O que demonstra: uso do helper PageProps tipado sem import manual.
// app/ui/post.tsx
import Link from 'next/link'

export default async function Posts() {
  const posts = await getPosts()
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}
  • O que demonstra: navegação entre páginas com prefetch automático.

Reference Tables

Quando usarAPI
Carregar dados da página (paginação, filtro no banco)prop searchParams
Filtrar lista já carregada, só no clientuseSearchParams
Ler search params em callback/event handler sem re-rendernew URLSearchParams(window.location.search)

Anti-patterns

  • Esquecer await em params/searchParams: ambos são Promise no App Router atual, acessar direto sem await quebra o tipo e o runtime.
  • Usar useSearchParams quando o dado devia vir do servidor: se o filtro precisa consultar banco/API, use a prop searchParams da page, não o hook client-side.

Key Takeaways

  1. page define UI de rota; layout define UI compartilhada que não re-renderiza na navegação e se aninha pela hierarquia de pastas.
  2. Root layout é obrigatório e único ponto que precisa de <html>/<body> (a menos que existam múltiplos, via route groups).
  3. [slug] cria rota dinâmica; params e searchParams chegam como Promise e precisam de await.
  4. <Link> é o mecanismo primário de navegação, com prefetch automático ao entrar no viewport ou hover.
  5. PageProps/LayoutProps eliminam a necessidade de tipar manualmente params/children/slots, são gerados automaticamente.

Connects To

  • Linking and Navigating: aprofunda o comportamento de prefetch e streaming do <Link> usado aqui.
  • Project Structure: define as convenções de arquivo (page, layout) usadas nesta página.