Next.js: Navegação: Link e API Programática
Última atualização: 2026-08-26
A navegação é como um sistema de metrô — existem linhas automatizadas (componentes Link), opções para controle manual (navegação programática), trens expressos para trajetos rápidos (soft navigation) e rotas de transferência (hard navigation).
1. O Que Você Vai Aprender
- Usos principais do componente
<Link>:prefetch,scroll,replace - Navegação Programática com
useRouter:push,replace,back,forward,refresh - Casos de Uso da Função
redirect()e do Componente<Redirect> - Os Princípios e Diferenças Entre Soft Navigation e Hard Navigation
- Opções de Implementação para Indicadores de Carregamento de Navegação
2. Uma História Real de um Desenvolvedor Júnior
(1) Ponto de Dor: Experiência de navegação ruim entre páginas
Charlie tem desenvolvido recentemente um site de e-commerce usando Next.js e descobriu que a experiência de navegação é ruim:
"Quando um usuário clica no link de um produto na página inicial, a página fica em branco por 1 segundo antes de carregar. Toda vez que o usuário clica em 'Voltar', a página inteira recarrega. Além disso, há um bug — se um usuário preenche metade de um formulário, clica acidentalmente no link de um produto e depois clica em 'Voltar', todos os dados do formulário são perdidos."
Perguntas específicas:
| Problema | Impacto | Feedback do Usuário |
|---|---|---|
| Tela em branco ao trocar de página | Navegação truncada | "Demora muito para clicar em um link" |
| Perda de Dados do Formulário | Usuário redigita os dados | "Preenchi até a metade, mas quando voltei, sumiu" |
| Pré-carregamento não é inteligente | Não pré-carrega páginas visitadas com frequência | "A transição mais lenta é da página inicial para a de detalhes do produto" |
| Posição de Rolagem Reiniciada | Volta ao topo após paginar na página de lista | "Tenho que rolar para baixo toda vez" |
(2) Soluções com a Navegação do Next.js
Componente Link com pré-busca automática + preservação de estado via Soft Navigation + scroll={false} para preservar a posição de rolagem.
// Navegação Otimizada na Página de Lista de Produtos
<Link
href={`/products/${product.id}`}
prefetch={true}
scroll={false}
className="block p-4 border rounded hover:shadow"
>
{product.title}
</Link>
(3) Ganhos
| Dimensão | Antes da Otimização (Tag <a> Padrão) |
Após Otimização (Componente <Link>) |
|---|---|---|
| Velocidade de Carregamento da Página | 1–2 segundos (tela em branco) | Instantâneo (cache pré-buscado) |
| Persistência de Dados do Formulário | Perdidos ao descarregar a página | Preservados no Soft Nav |
| Posição de Rolagem Mantida | Volta ao Topo | Retenção Exata |
| Avaliação da Experiência do Usuário | 3,2/5 | 4,8/5 |
3. Componente Link
(1) Uso Básico
graph LR
A[Componente Link] --> B[Navegação no Cliente<br/>Sem recarregamento completo da página]
A --> C[Pré-busca Automática<br/>Links dentro da viewport]
A --> D[Controle de Rolagem<br/>scroll={false}]
A --> E[Substituição de Histórico<br/>replace]
style A fill:#cce5ff
style B fill:#d4edda
▶ Exemplo: Navegação Básica com Link
Saída:
Diagrama da navegação no lado do cliente usando o componente Link.
// ============================================
// Uso Básico do Componente Link
// ============================================
import Link from "next/link";
export default function Navigation() {
return (
<nav className="flex gap-6 p-4 bg-white shadow-sm">
{/* Navegação Básica */}
<Link href="/" className="text-blue-600 hover:underline">
Início
</Link>
{/* Roteamento Dinâmico */}
<Link href="/products/42" className="text-blue-600 hover:underline">
Produto 42
</Link>
{/* Com parâmetros de consulta */}
<Link
href="/products?category=electronics&sort=price"
className="text-blue-600 hover:underline"
>
Eletrônicos
</Link>
{/* URL Completa */}
<Link
href="https://help.example.com"
className="text-blue-600 hover:underline"
>
Central de Ajuda
</Link>
</nav>
);
}
Saída:
Renderiza: Links de navegação usando o componente Link do Next.js para roteamento no lado do cliente.
Saída:
O navegador exibe 4 links azuis:
Início → /
Produto 42 → /products/42
Eletrônicos → /products?category=electronics&sort=price
Central de Ajuda → https://help.example.com (Link Externo)
(2) prefetch
Por padrão, o componente Link pré-carrega links dentro da viewport. O comportamento de pré-carregamento difere entre o servidor e o cliente:
| Ambiente | prefetch={true} |
prefetch={false} |
|---|---|---|
| Renderização no servidor | Pré-busca dados da página e payload RSC | Não pré-busca |
| Página Estática | Pré-carrega a Página Inteira | Não Pré-carrega |
| Dentro da viewport | Comportamento padrão | Nunca pré-carrega |
▶ Exemplo: Controlando o Comportamento de prefetch
Saída:
A página renderiza conforme descrito acima, com a UI atualizando com base no comportamento descrito.
// ============================================
// Controlar o Comportamento de Prefetch do Link
// ============================================
import Link from "next/link";
export default function ProductList() {
const products = [
{ id: 1, name: "Mouse Sem Fio" },
{ id: 2, name: "Teclado" },
{ id: 3, name: "Monitor" },
];
return (
<div className="p-8">
<h1 className="text-2xl font-bold mb-4">Produtos</h1>
{/* prefetch padrão: pré-carrega automaticamente links dentro da viewport */}
{products.map(p => (
<Link
key={p.id}
href={`/products/${p.id}`}
className="block p-4 border-b hover:bg-gray-50"
>
{p.name}
</Link>
))}
{/* Desativar prefetch: Adequado para páginas não usadas com frequência */}
<Link
href="/archive"
prefetch={false}
className="block mt-4 text-gray-500"
>
Ver Arquivo (produtos antigos)
</Link>
{/* Prefetch Forçado: Adequado para a próxima página que você está prestes a visitar */}
<Link
href="/checkout"
prefetch={true}
className="block mt-4 px-6 py-2 bg-blue-600 text-white text-center rounded"
>
Ir para o Checkout
</Link>
</div>
);
}
Saída:
Mapeia os produtos para renderizar a lista.
Conteúdo: Produtos
Saída:
Após o carregamento da página, isso pode ser observado no console de rede:
1. /products/1, /products/2, /products/3 Pré-buscados (dentro da viewport)
2. /archive Não pré-buscado (prefetch={false})
3. /checkout Pré-buscado (prefetch={true}, mesmo não estando na viewport)
Quando um usuário clica no link:
- Páginas pré-buscadas → Exibição em Tempo Real (lidas do cache)
- Páginas Não Pré-buscadas → Exibidas após a requisição de rede
(3) Controles de Rolagem
graph LR
A[Gatilho de Navegação] --> B{Propriedade scroll}
B -->|scroll=true Padrão| C[Rolar para o topo da nova página]
B -->|scroll=false| D[Manter a posição de rolagem atual]
style C fill:#f8d7da
style D fill:#d4edda
▶ Exemplo: scroll={false} para manter a posição de rolagem
Saída:
Diagrama: Gatilho de Navegação; Rolar para o topo da nova página; Manter a posição de rolagem atual.
// ============================================
// Lista de Produtos + Janela Modal: scroll=false Mantém a lista no lugar
// Usuários clicam em um produto para ver seus detalhes, a lista não rola ao retornar
// ============================================
import Link from "next/link";
export default function ProductGrid() {
const products = Array.from({ length: 20 }, (_, i) => ({
id: i + 1,
name: `Produto ${i + 1}`,
}));
return (
<div className="p-8">
<h1 className="text-2xl font-bold mb-6">Catálogo de Produtos</h1>
<div className="grid grid-cols-4 gap-4">
{products.map(p => (
<Link
key={p.id}
href={`/products/${p.id}`}
scroll={false}
className="border p-4 rounded hover:shadow-lg"
>
<div className="h-32 bg-gray-100 rounded" />
<p className="mt-2 font-medium">{p.name}</p>
</Link>
))}
</div>
</div>
);
}
Saída:
Mapeia os produtos para renderizar a lista.
Conteúdo: Catálogo de Produtos
Saída:
1. O usuário rolou até o 3º item por página (Rolou 2000px para baixo)
2. Clica no 15º produto para ir à página de detalhes
3. Clica no botão Voltar do navegador
4. Volta para a página de lista, mantém a posição de rolagem em 2000px (Sem "Voltar ao Topo")
5. Comparação: Sem scroll={false}, retorna ao topo toda vez
(4) replace: Substituir histórico
| Ação | push (padrão) |
replace |
|---|---|---|
| Histórico do Navegador | Adiciona uma nova entrada | Substitui a entrada atual |
| Comportamento do Botão Voltar | Retorna à página anterior | Vai para a página que foi substituída |
| Após envio de formulário | Não pode retornar à página do formulário | Pode retornar (pulando a página do formulário) |
▶ Exemplo: Usando replace em um cenário de formulário
Saída:
O componente renderiza a UI descrita no navegador.
// ============================================
// replace Substituição de Histórico: Você não pode retornar à página do formulário após enviar.
// ============================================
import Link from "next/link";
export default function CheckoutPage() {
return (
<div className="max-w-md mx-auto p-8">
<h1 className="text-2xl font-bold mb-6">Checkout</h1>
<div className="space-y-4">
<input placeholder="Número do cartão" className="w-full p-3 border rounded" />
<input placeholder="Data de validade" className="w-full p-3 border rounded" />
<input placeholder="CVV" className="w-full p-3 border rounded" />
</div>
{/* Usando replace: Uma vez enviado, você não pode retornar a esta página. */}
<Link
href="/order-confirmation"
replace
className="block mt-6 w-full p-3 bg-blue-600 text-white text-center rounded"
>
Finalizar Pedido
</Link>
<p className="text-sm text-gray-500 mt-2 text-center">
Após finalizar o pedido, o botão voltar pulará esta página
</p>
</div>
);
}
Saída:
Conteúdo: Checkout | Finalizar Pedido | Após finalizar o pedido, o botão voltar pu
Saída:
Fluxo do Usuário:
1. Início → Carrinho de Compras → Checkout → Página de Confirmação
2. Toque em "Finalizar Pedido" na página de checkout
3. O endereço do navegador muda para /order-confirmation
4. O usuário clica no botão Voltar
5. Pula a página de checkout, vai diretamente para o carrinho de compras
6. Evita que usuários retornem acidentalmente à página de checkout e enviem o pedido novamente
4. Navegação Programática com useRouter
(1) Referência Rápida da API
graph TB
A[useRouter] --> B[push(url) - Navegar para uma nova página]
A --> C[replace(url) - Substituir Histórico Atual]
A --> D[back() - Voltar]
A --> E[forward() - Avançar]
A --> F[refresh() - Atualizar esta página]
A --> G[prefetch(url) - Pré-busca Programática]
style A fill:#cce5ff
| Método | Parâmetros | Descrição | Comportamento do Navegador |
|---|---|---|---|
push |
href: string |
Navegar para a nova URL | Adiciona ao histórico |
replace |
href: string |
Substituir Histórico Atual | Substitui o Histórico |
back |
Nenhum | Voltar no Navegador | Igual a history.back() |
forward |
Nenhum | Avançar no Navegador | Igual a history.forward() |
refresh |
Nenhum | Atualizar esta página | Renderização no Servidor (RSC) |
prefetch |
href: string |
Pré-buscar Página | Armazena Payload RSC em Cache |
▶ Exemplo: Navegação Programática
Saída:
Diagrama da navegação no lado do cliente usando o componente Link.
// ============================================
// Exemplo Completo de Navegação Programática com useRouter
// ============================================
'use client';
import { useRouter } from "next/navigation";
export default function NavigationBar({ userId }: { userId: string }) {
const router = useRouter();
return (
<div className="p-4 bg-white shadow-sm">
<div className="flex gap-4 max-w-4xl mx-auto">
{/* push: Ir para a Página Inicial */}
<button
onClick={() => router.push("/")}
className="px-4 py-2 bg-blue-600 text-white rounded"
>
Início
</button>
{/* push: Roteamento Dinâmico */}
<button
onClick={() => router.push(`/users/${userId}`)}
className="px-4 py-2 bg-gray-600 text-white rounded"
>
Perfil
</button>
{/* replace: Substituir a página atual */}
<button
onClick={() => router.replace("/login")}
className="px-4 py-2 bg-red-600 text-white rounded"
>
Sair
</button>
{/* back/forward: Histórico de Navegação */}
<button
onClick={() => router.back()}
className="px-4 py-2 border rounded"
>
← Voltar
</button>
<button
onClick={() => router.forward()}
className="px-4 py-2 border rounded"
>
Avançar →
</button>
{/* refresh: Atualizar esta página (Re-renderização no Servidor) */}
<button
onClick={() => router.refresh()}
className="px-4 py-2 border rounded"
>
Atualizar ↻
</button>
</div>
</div>
);
}
Saída:
NavigationBar renderiza sua UI.
Saída:
Clique em cada botão:
[Início] → Navega para /
[Perfil] → Navega para /users/123
[Sair] → Substitui o histórico atual por /login (Sem Retorno)
[← Voltar] → Botão Voltar do Navegador
[Avançar] → Botão Avançar do Navegador
[Atualizar] → Atualiza esta página (RSC Renderiza Novamente, Não causa recarregamento completo da página)
▶ Exemplo: Navegação Após Envio de Formulário
Saída:
A página renderiza conforme descrito acima, com a UI atualizando com base no comportamento descrito.
// ============================================
// Envio de Formulário: Verificação → salvar → Navegação Programática
// ============================================
'use client';
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function CreateProjectForm() {
const router = useRouter();
const [saving, setSaving] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setSaving(true);
try {
// Simulação de Chamada API
await new Promise(resolve => setTimeout(resolve, 1500));
// Após conclusão bem-sucedida, navega para a página do novo projeto
router.push("/projects/42");
// e atualiza o cache de dados
router.refresh();
} catch (err) {
console.error("Falha ao criar projeto:", err);
alert("Falha ao criar projeto. Por favor, tente novamente.");
} finally {
setSaving(false);
}
}
return (
<form onSubmit={handleSubmit} className="max-w-lg mx-auto p-8 space-y-4">
<h1 className="text-2xl font-bold">Criar Projeto</h1>
<input
name="name"
placeholder="Nome do projeto"
className="w-full p-3 border rounded"
required
/>
<textarea
name="description"
placeholder="Descrição"
className="w-full p-3 border rounded h-32"
/>
<button
type="submit"
disabled={saving}
className="w-full p-3 bg-blue-600 text-white rounded disabled:opacity-50"
>
{saving ? "Criando..." : "Criar Projeto"}
</button>
</form>
);
}
Saída:
Formulário com: name.
Conteúdo: Criar Projeto
Saída:
1. O usuário insere o nome e a descrição do projeto
2. Clica no botão "Criar Projeto"
3. O botão muda para "Criando..." (Desabilitado)
4. Após 1,5s (atraso simulado da API)
5. Navegação da Página para /projects/42
6. Atualiza os Dados da Lista de Projetos (Inclui projetos recém-criados)
5. redirect() e <Redirect>
(1) Dois Tipos de Redirecionamento
graph TB
A[Requisições de Redirecionamento] --> B[Lado do Servidor<br/>redirect()]
A --> C[Lado do Cliente<br/><Redirect>]
B --> D[Server Action / Route Handler]
B --> E[Server Component]
C --> F[Client Component]
C --> G[Ao usar renderização condicional]
style B fill:#d4edda
style C fill:#cce5ff
| Método | Onde Usar | Quando Disparar | Performance |
|---|---|---|---|
redirect() |
Server Actions / Server Components | Durante a Resposta do Servidor | Redirecionamento no Servidor, Zero Sobrecarga no Cliente |
<Redirect> |
Client Components | Durante a renderização | Redirecionamento no lado do cliente, mudanças de rota |
6. Soft Navigation vs Hard Navigation
(1) Comparação
graph TB
subgraph "Soft Navigation (Link/useRouter)"
A[Roteamento no Lado do Cliente] --> B[Navegação de Página<br/>Sem recarregamento completo]
B --> C[layout Mantém Montado]
B --> D[Estado React Preservado]
B --> E[Substituição do Payload RSC]
end
subgraph "Hard Navigation (Atualizar toda a página do navegador)"
F[Carregamento Completo da Página no Navegador] --> G[Navegação de Página<br/>Atualizar a página inteira]
G --> H[layout Remonta]
G --> I[Reinicia Todos os Estados]
G --> J[Carregamento Completo de JS/CSS]
end
style A fill:#d4edda
style F fill:#f8d7da
| Característica | Soft Navigation | Hard Navigation |
|---|---|---|
| Método de Disparo | <Link>, useRouter() |
Atualização do navegador, tag <a>, window.location |
| Atualiza Página Inteira | ❌ Não | ✅ Sim |
| Layout Preservado | ✅ Preservado | ❌ Remontado |
| Payload RSC | Atualização Incremental | Download Completo |
| Performance | Tempo real | 500 ms–2 s |
| Estado Mantido | ✅ | ❌ |
7. Indicador de Carregamento de Navegação
(1) Plano de Implementação
graph TB
A[Gatilho de Navegação] --> B[Indicador de Carregamento]
B --> C[Barra de Progresso Superior<br/>Estilo NProgress]
B --> D[Suspense fallback<br/>Exibição de Estrutura Wireframe]
B --> E[loading.tsx<br/>Carregamento em Nível de Página]
style A fill:#cce5ff
style B fill:#f8d7da
8. Exemplo Completo: Sistema de Navegação de E-commerce
// ============================================
// Exemplo Abrangente: Um Sistema de Navegação Completo para E-commerce
// Cobrindo Link, useRouter, redirect, Estado de Carregamento de Navegação
// ============================================
// src/app/layout.tsx — Barra de Navegação Global
import Link from "next/link";
import { CartCount } from "./CartCount";
export default function RootLayout({ children }) {
return (
<html lang="pt-BR">
<body>
<header className="bg-white shadow-sm sticky top-0 z-40">
<div className="max-w-6xl mx-auto px-4 py-3 flex items-center justify-between">
<Link href="/" className="text-2xl font-bold text-blue-600">
ShopHub
</Link>
<nav className="hidden md:flex gap-6">
<Link href="/products" className="hover:text-blue-600">
Produtos
</Link>
<Link href="/categories" className="hover:text-blue-600">
Categorias
</Link>
<Link href="/deals" prefetch={false} className="hover:text-blue-600">
Ofertas
</Link>
<Link href="/about" className="hover:text-blue-600">
Sobre
</Link>
</nav>
<div className="flex items-center gap-4">
<Link href="/search" className="text-gray-600 hover:text-blue-600">
Buscar
</Link>
<Link href="/cart" className="relative text-gray-600 hover:text-blue-600">
Carrinho
<CartCount />
</Link>
<Link
href="/account"
className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm"
>
Entrar
</Link>
</div>
</div>
</header>
<main className="max-w-6xl mx-auto px-4 py-8">
{children}
</main>
</body>
</html>
);
}
// src/app/products/[id]/page.tsx — Detalhes do Produto (Inclui lógica de navegação)
'use client';
import { useRouter } from "next/navigation";
import Link from "next/link";
export default function ProductDetail({ params }) {
const router = useRouter();
async function handleAddToCart() {
await fetch("/api/cart", {
method: "POST",
body: JSON.stringify({ productId: params.id }),
});
// Atualiza a quantidade no carrinho de compras após adicionar um item
router.refresh();
}
async function handleBuyNow() {
await fetch("/api/cart", {
method: "POST",
body: JSON.stringify({ productId: params.id, quantity: 1 }),
});
// Comprar Agora → Ir para o Checkout (usa replace para evitar retornar à página do produto)
router.replace("/checkout");
}
return (
<div>
{/* Navegação Breadcrumb */}
<nav className="text-sm text-gray-500 mb-6">
<Link href="/" className="hover:text-blue-600">Início</Link>
<span className="mx-2">/</span>
<Link href="/products" className="hover:text-blue-600">Produtos</Link>
<span className="mx-2">/</span>
<span className="text-gray-900">{params.id}</span>
</nav>
<div className="flex gap-8">
<div className="w-1/2">
<img
src={`https://picsum.photos/seed/${params.id}/400/400`}
alt="Produto"
className="w-full rounded-lg"
/>
</div>
<div className="w-1/2">
<h1 className="text-3xl font-bold">Produto #{params.id}</h1>
<p className="text-2xl text-green-600 font-bold mt-4">R$ 49,99</p>
<p className="text-gray-600 mt-4">
Produto de alta qualidade com recursos premium.
</p>
<div className="flex gap-4 mt-8">
<button
onClick={handleAddToCart}
className="flex-1 px-6 py-3 border-2 border-blue-600 text-blue-600 rounded-lg hover:bg-blue-50"
>
Adicionar ao Carrinho
</button>
<button
onClick={handleBuyNow}
className="flex-1 px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Comprar Agora
</button>
</div>
<div className="mt-8 border-t pt-6">
<Link
href={`/products/${Number(params.id) - 1}`}
scroll={false}
className="text-blue-600 hover:underline"
>
← Produto Anterior
</Link>
<Link
href={`/products/${Number(params.id) + 1}`}
scroll={false}
className="text-blue-600 hover:underline float-right"
>
Próximo Produto →
</Link>
</div>
</div>
</div>
</div>
);
}
// src/app/CartCount.tsx — Exibição da Quantidade no Carrinho de Compras
export async function CartCount() {
const cart = await fetch("https://api.example.com/cart");
const itemCount = cart?.items?.length ?? 0;
if (itemCount === 0) return null;
return (
<span className="absolute -top-2 -right-2 bg-red-500 text-white text-xs w-5 h-5 rounded-full flex items-center justify-center">
{itemCount}
</span>
);
}
Saída Esperada:
Barra de Navegação (Fixada no topo):
[ShopHub] Produtos Categorias Ofertas Sobre [Buscar] Carrinho(3) [Entrar]
Página de Detalhes do Produto (/products/1):
Início / Produtos / 1
[Imagens do Produto] [Detalhes do Produto]
Produto #1
R$ 49,99
[Adicionar ao Carrinho] [Comprar Agora]
← Produto Anterior | Próximo Produto →
Comportamento de Navegação:
- Clicar em Produtos → Soft Nav, Troca Instantânea de Página
- Clicar em Ofertas → Sem pré-busca (prefetch=false), Mas a navegação ainda é rápida
- Adicionar ao Carrinho → router.refresh(), Atualização do Ícone do Carrinho
- Comprar Agora → router.replace("/checkout"), Substituição de Histórico
❓ Perguntas Frequentes
P: Qual é a diferença entre o componente
Linke a tag<a>? R: O componenteLinkgerencia o roteamento no lado do cliente sem disparar um recarregamento completo da página, preserva o layout e suporta pré-carregamento. A tag<a>dispara um recarregamento completo da página (hard navigation), fazendo com que todo o estado React seja perdido. O Next.js usaLinkpara todo o roteamento interno.
P: Por que componentes que usam
useRouterprecisam incluir'use client'? R:useRouteré um hook do React e só pode ser usado em componentes cliente. Componentes servidor não têm acesso às APIs do navegador (comohistoryelocation), então os hooks relacionados ao roteamento são executados no lado do cliente.
P: Qual é a diferença entre
router.refresh()ewindow.location.reload()? R:router.refresh()é a atualização suave do Next.js — ele solicita novamente o payload RSC do servidor, atualizando apenas as partes alteradas enquanto preserva o estado do lado do cliente (comouseStateeContext).window.location.reload()realiza um recarregamento completo da página, causando a perda de todo o estado e exigindo o recarregamento completo de JS e CSS.
P: O prefetch do Link também é acionado em dispositivos móveis? R: Sim. O prefetch é acionado para links dentro da viewport, inclusive em dispositivos móveis. No entanto, o Next.js leva em consideração o uso de dados do usuário — pode não pré-buscar páginas grandes em redes lentas (2G/3G). Você também pode controlar isso manualmente usando
prefetch={false}.
P: Quando
redirect()e<Redirect>devem ser usados? R:redirect()é usado no lado do servidor (Server Actions, Server Components, Route Handlers) para enviar uma resposta 303/307. Para redirecionamento condicional no lado do cliente, use lógica de controle de acesso (exiba uma mensagem de "Acesso Negado" + um botão de navegação) em vez do componente<Redirect>.
P: O que devo fazer se a URL mudar, mas o conteúdo da página permanecer o mesmo durante a navegação? R: Isso geralmente é causado pelo uso da mesma React key ou cache. Você pode tentar o seguinte: 1) Use uma key diferente no componente da página para forçar a reconstrução; 2) Chame
router.refresh()para atualizar os dados do lado do servidor; 3) Verifique se os dados estão sendo armazenados em cache pelo layout.
📖 Resumo
- O componente
<Link>é a solução de navegação preferida do Next.js, suportando pré-carregamento automático e transições no lado do cliente prefetch={true}Pré-carrega links dentro da viewport,prefetch={false}Desativa o pré-carregamentoscroll={false}Mantém a posição de rolagem; adequado para páginas de lista e páginas de detalhesreplaceSobrescreve o histórico do navegador para evitar navegação acidental de volta de páginas de formuláriouseRouterFornece navegação programática:push,replace,back,forward,refreshredirect()Para uso no lado do servidor; envia uma resposta de redirecionamento 303/307- Soft Navigation preserva o layout e o estado, enquanto Hard Navigation recarrega a página inteira
router.refresh()é um recurso especial de soft navigation: atualiza os dados RSC sem alterar a URL
📝 Exercícios
-
Exercício Básico (⭐): Crie cinco links na página (Início, Sobre, Contato, Lista de Produtos, Detalhes do Produto #42) e observe quais URLs são pré-carregadas na aba Network do navegador.
-
Exercício Avançado (⭐⭐): Implemente um fluxo de trabalho "Login → Dashboard": Use uma Server Action para verificar o login; se bem-sucedido, use
redirect()para redirecionar para o dashboard; se malsucedido, useredirect()para retornar à página de login e inclua os parâmetros de erro. -
Desafio (⭐⭐⭐): Implemente uma página de lista com rolagem infinita. Quando um usuário clicar em um produto para ir à página de detalhes, use
scroll={false}para preservar a posição de rolagem; quando o usuário retornar, a lista deve permanecer em sua posição anterior. Userouter.back()para implementar a navegação de volta.