Capítulo 4 de 456
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>.
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.app, obrigatório, precisa conter <html> e <body>./blog/[slug] = root + blog + [slug]); layouts se aninham automaticamente na mesma hierarquia.[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.// 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>
)
}
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>
}
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>
)
}
| Quando usar | API |
|---|---|
| Carregar dados da página (paginação, filtro no banco) | prop searchParams |
| Filtrar lista já carregada, só no client | useSearchParams |
| Ler search params em callback/event handler sem re-render | new URLSearchParams(window.location.search) |
await em params/searchParams: ambos são Promise no App Router atual, acessar direto sem await quebra o tipo e o runtime.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.page define UI de rota; layout define UI compartilhada que não re-renderiza na navegação e se aninha pela hierarquia de pastas.<html>/<body> (a menos que existam múltiplos, via route groups).[slug] cria rota dinâmica; params e searchParams chegam como Promise e precisam de await.<Link> é o mecanismo primário de navegação, com prefetch automático ao entrar no viewport ou hover.PageProps/LayoutProps eliminam a necessidade de tipar manualmente params/children/slots, são gerados automaticamente.<Link> usado aqui.page, layout) usadas nesta página.