React: Introdução ao React Router
Última atualização: 2026-08-26
Tom está desenvolvendo um painel de administração de comércio eletrônico. Inicialmente, ele usou
useStatepara alternar entre as “páginas” — uma variável de estado para cada uma: página inicial, lista de produtos e detalhes do pedido. À medida que o número de páginas aumentou para 10, a lógica de estado tornou-se uma confusão, e a barra de URL permaneceu presa em/, tornando impossível compartilhar diretamente um link para uma página específica. Ele percebeu: estava faltando uma solução profissional de roteamento.
1. O que você vai aprender
- Critérios para escolher entre o BrowserRouter e o HashRouter
- Os mecanismos de correspondência de caminhos para “Routes” e “Route”
- Navegação declarativa com Link e NavLink
- useParams: Lê parâmetros dinâmicos de URL
- Rotas aninhadas e modo de layout de tomadas
2. Diagramas conceituais
flowchart LR
A[BrowserRouter<br/>Routing Container] --> B[Routes<br/>Routing Table]
B --> C["Route path='/'<br/>→ Home"]
B --> D["Route path='/products'<br/>→ ProductList"]
B --> E["Route path='/products/:id'<br/>→ ProductDetail"]
B --> F["Route path='*'<br/>→ NotFound"]
C --> G[Rendering Component]
D --> G
E --> G
F --> G
style A fill:#e1f5fe,stroke:#0288d1
style B fill:#fff3e0,stroke:#f57c00
style G fill:#e8f5e9,stroke:#388e3c
Um usuário acessa uma URL diferente → O BrowserRouter a captura → O sistema de roteamento identifica a rota mais adequada → O componente correspondente é renderizado.
3. Um cenário da vida real
O painel de administração do Tom precisa de três páginas principais: Painel de Controle, Gerenciamento de Produtos e Configurações do Sistema. Além disso, a seção Gerenciamento de Produtos inclui duas subpáginas: Lista de Produtos e Detalhes do Produto. Ele quer que cada página tenha uma URL exclusiva para que os usuários possam navegar usando os botões “Avançar” e “Voltar” do navegador.
(1) Seleção de um modo de roteamento
O React Router oferece dois modos de roteamento, que diferem fundamentalmente na forma como lidam com as URLs:
| Padrão | Exemplo de URL | Princípio | Casos de uso |
|---|---|---|---|
BrowserRouter |
example.com/users |
Manipulação de URLs usando a API History | Projetos nos quais o servidor pode configurar a reescrita de URLs |
HashRouter |
example.com/#/users |
Como evitar solicitações ao servidor acionadas por alterações no hash da URL | Hospedagem estática (GitHub Pages, CDN) |
Recomendações: Para projetos que possam ser hospedados em um servidor, use sempre BrowserRouter — isso resulta em uma URL mais simples e é mais favorável ao SEO. Para hospedagem estática, use HashRouter.
▶ Exemplo 1: Configuração básica de roteamento
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'
function Home() {
return <h2>Dashboard Home Page</h2>
}
function ProductList() {
return <h2>Product List</h2>
}
function Settings() {
return <h2>System Settings</h2>
}
function NotFound() {
return <h2>404 — Page Not Found</h2>
}
function App() {
return (
<BrowserRouter>
<nav style={{ display: 'flex', gap: '1rem', padding: '1rem', background: '#f0f0f0' }}>
<Link to="/">Home</Link>
<Link to="/products">Product Management</Link>
<Link to="/settings">System Settings</Link>
</nav>
<main style={{ padding: '1rem' }}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<ProductList />} />
<Route path="/settings" element={<Settings />} />
<Route path="*" element={<NotFound />} />
</Routes>
</main>
</BrowserRouter>
)
}
export default App
Como funciona: Quando você clica em um link de navegação, a URL muda e o conteúdo da página é atualizado, mas o navegador não recarrega a página inteira — essa é a essência do roteamento em SPAs.
Sobre path="*": O curinga * corresponde a todos os caminhos não definidos nas rotas anteriores; ele é normalmente colocado no final da lista de rotas para gerar uma página 404. No React Router v6, * só pode aparecer como o último caractere de um caminho.
(2) Status de ativação do NavLink
| Componente de navegação | Finalidade | Estilo de ativação | Casos de uso |
|---|---|---|---|
<Link to="/path"> |
Navegação declarativa | Nenhuma | Links de navegação gerais |
<NavLink to="/path"> |
Navegação com estado ativo | isActive Callback |
Destaque da barra lateral/navegação superior |
navigate('/path') |
Redirecionamentos programáticos | — | Redirecionamentos após o login, redirecionamentos após o envio de formulários |
<Navigate to="/path" /> |
Redirecionamento declarativo | — | Componente de redirecionamento condicional |
Tom quer destacar a página atual na barra de navegação para que os usuários possam ver claramente “onde estão”. O componente <NavLink> oferece o parâmetro isActive, que permite definir estilos dinamicamente com base na rota atual. Ele possui duas propriedades adicionais em comparação com <Link>: style e className suportam, ambas, a aceitação de uma função de retorno de chamada com as propriedades isActive e isPending.
▶ Exemplo 2: Barra de navegação com estilo ativo
import { NavLink } from 'react-router-dom'
function NavBar() {
const linkStyle = {
padding: '8px 16px',
textDecoration: 'none',
borderRadius: '6px',
transition: 'all 0.2s'
}
const activeStyle = {
...linkStyle,
backgroundColor: '#1976d2',
color: '#fff',
fontWeight: 'bold'
}
const inactiveStyle = {
...linkStyle,
color: '#333'
}
return (
<nav style={{ display: 'flex', gap: '12px', padding: '12px', background: '#fafafa' }}>
<NavLink
to="/"
style={({ isActive }) => (isActive ? activeStyle : inactiveStyle)}
end // Exact Match,Avoid "/" Match all that start with "/" Starting path
>
Home
</NavLink>
<NavLink
to="/products"
style={({ isActive }) => (isActive ? activeStyle : inactiveStyle)}
>
Product Management
</NavLink>
<NavLink
to="/settings"
style={({ isActive }) => (isActive ? activeStyle : inactiveStyle)}
>
System Settings
</NavLink>
</nav>
)
}
Ponto-chave: A propriedade end garante que o caminho / seja ativado somente quando houver uma correspondência exata; caso contrário, todos os caminhos acionarão o estilo de ativação da página inicial. O NavLink do className também suporta funções de retorno de chamada, tornando-o adequado para projetos que utilizam nomes de classes CSS.
(3) Compartilhamento de rotas e layouts aninhados
Tom descobriu que a página de gerenciamento de produtos continha duas subpáginas — “Lista de produtos” e “Adicionar produto” — que compartilhavam o mesmo layout da barra lateral. Escrever o código do layout repetidamente para cada subpágina seria redundante e difícil de manter. O roteamento aninhado do React Router, combinado com <Outlet>, resolve esse problema perfeitamente.
O conceito central do roteamento aninhado é que a rota pai define a estrutura de layout, e a rota filha insere o conteúdo por meio de outlets. O componente pai não se preocupa com o que a rota filha exibe especificamente; ele é responsável exclusivamente pela estrutura de layout.
▶ Exemplo 3: Rotas e pontos de saída aninhados
import { BrowserRouter, Routes, Route, Link, Outlet, useParams } from 'react-router-dom'
// Parent Layout Component — Shared Sidebar + Outlet
function ProductsLayout() {
return (
<div style={{ display: 'flex' }}>
<aside style={{ width: '200px', padding: '16px', background: '#f5f5f5' }}>
<h3>Product Management</h3>
<nav style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<Link to="list">Product List</Link>
<Link to="add">Add Item</Link>
</nav>
</aside>
<main style={{ flex: 1, padding: '16px' }}>
{/* The components of the child route are rendered here */}
<Outlet />
</main>
</div>
)
}
function ProductList() {
const products = [
{ id: 1, name: 'React Programming Books', price: 79 },
{ id: 2, name: 'TypeScript Guide', price: 59 },
{ id: 3, name: 'Node.js Real-World Experience', price: 69 }
]
return (
<div>
<h2>Product List</h2>
<ul>
{products.map(p => (
<li key={p.id}>
<Link to={`/products/detail/${p.id}`}>
{p.name} — ${p.price}
</Link>
</li>
))}
</ul>
</div>
)
}
function AddProduct() {
return (
<div>
<h2>Add Item</h2>
<form onSubmit={e => { e.preventDefault(); alert('Submission Successful!') }}>
<div><label>Product Name:<input name="name" /></label></div>
<div><label>Price:<input name="price" type="number" /></label></div>
<button type="submit">Submit</button>
</form>
</div>
)
}
function ProductDetail() {
const { id } = useParams()
return <h2>Product Details(ID:{id})</h2>
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<h2>Home</h2>} />
{/* Nested Routes:Parent Route with Layout,Subnet routing is enabled Outlet Rendering */}
<Route path="/products" element={<ProductsLayout />}>
<Route index element={<ProductList />} /> {/* /products Default Display */}
<Route path="list" element={<ProductList />} /> {/* /products/list */}
<Route path="add" element={<AddProduct />} /> {/* /products/add */}
<Route path="detail/:id" element={<ProductDetail />} /> {/* /products/detail/1 */}
</Route>
<Route path="*" element={<h2>404 Not found</h2>} />
</Routes>
</BrowserRouter>
)
}
Lógica de fluxo: Acessar /products/list → ProductsLayout (renderizar a barra lateral) → Outlet (exibir o componente ProductList nesse local). A estrutura da URL corresponde exatamente à estrutura dos componentes, tornando-a clara e fácil de manter.
Sobre a rota de índice: A rota index é a subrota padrão para o caminho pai. Quando se acessa /products e nenhum subcaminho corresponde (nem list nem add correspondem), o conteúdo da rota de índice é exibido no Outlet. Isso garante que o caminho pai não exiba uma área em branco.
4. Roteamento dinâmico e parâmetros de caminho
| Padrão de caminho | Exemplo de URL | Valor de retorno de useParams | Descrição |
|---|---|---|---|
/users/:id |
/users/42 |
{ id: '42' } |
Parâmetro dinâmico único |
/users/:userId/posts/:postId |
/users/42/posts/99 |
{ userId: '42', postId: '99' } |
Parâmetros dinâmicos de múltiplos estágios |
/files/* |
/files/a/b/c |
{ '*': 'a/b/c' } |
Caractere curinga que corresponde ao caminho restante |
/categories/:catId/:tab? |
É necessário definir duas rotas | { catId, tab } |
Parâmetros opcionais (sem suporte nativo) |
O roteamento dinâmico é uma das características mais importantes de um sistema de roteamento. A página de detalhes do produto do Tom precisa exibir conteúdos diferentes com base no ID do produto, e ele não tem como criar uma rota para cada ID de produto — é aí que entra a sintaxe :param para definir caminhos dinâmicos.
(1) Usando useParams
:id é um marcador de lugar para um parâmetro dinâmico; o valor real é extraído da URL por meio do gancho useParams.
function UserDetail() {
const { userId, postId } = useParams()
return <p>User {userId} Article {postId}</p>
}
// URL: /users/42/posts/99 → userId=42, postId=99
▶ Exemplo 4: Página de detalhes do produto
import { useParams, Link, useNavigate } from 'react-router-dom'
// Simulated Product Data
const products = [
{ id: '1', name: 'React Programming Books', price: 79, description: 'Mastering It from Scratch React 18 Development' },
{ id: '2', name: 'TypeScript Guide', price: 59, description: 'Systematic Study TypeScript Type System' },
{ id: '3', name: 'Node.js Real-World Experience', price: 69, description: 'Backend Development: From Beginner to Advanced' }
]
function ProductDetail() {
const { id } = useParams()
const navigate = useNavigate()
const product = products.find(p => p.id === id)
if (!product) {
return (
<div>
<h2>The product does not exist.</h2>
<button onClick={() => navigate('/products')}>Back to Product List</button>
</div>
)
}
return (
<div>
<h2>{product.name}</h2>
<p className="price">Price:${product.price}</p>
<p className="desc">{product.description}</p>
<Link to="/products">← Back to List</Link>
</div>
)
}
Observação: Ao usar parâmetros dinâmicos, é preciso levar em conta situações em que “um valor de parâmetro não tem dados correspondentes”. O ramo if (!product) no código acima lida com dados vazios para evitar que a página exiba uma tela em branco ao tentar acessar um ID inexistente.
(2) Parâmetros dinâmicos multissegmentos
Um caminho pode conter vários parâmetros dinâmicos, o que é comum em cenários que envolvem recursos aninhados:
// Route Definitions
<Route path="/categories/:catId/products/:prodId" element={<ProductView />} />
// Extracted from the component
function ProductView() {
const { catId, prodId } = useParams()
// URL: /categories/electronics/products/42
// catId = "electronics", prodId = "42"
return <h2>Categories {catId} Items under {prodId}</h2>
}
(3) Parâmetros opcionais e caracteres curinga
O React Router v6 não oferece suporte direto a parâmetros opcionais, mas é possível obter um efeito semelhante de duas maneiras:
// Method 1:Define two Route(Recommendations)
<Route path="/categories/:catId" element={<CategoryPage />} />
<Route path="/categories/:catId/:tab" element={<CategoryPage />} />
// Method 2:Make the determination within the component itself
function CategoryPage() {
const { catId, tab } = useParams()
const activeTab = tab || 'overview' // Default value
return <h2>Categories {catId} - {activeTab}</h2>
}
A vantagem da Opção 1 é que a URL é semanticamente clara, enquanto a Opção 2 é mais concisa, mas reduz a legibilidade da URL.
(4) Uma explicação detalhada das prioridades de correspondência de caminhos
A correspondência de caminhos no React Router v6 se baseia em um algoritmo de pontuação, em vez da abordagem do tipo “primeiro a chegar, primeiro a ser atendido” usada em frameworks tradicionais. Compreender essas regras pode ajudar a solucionar problemas em que as rotas não estão funcionando como esperado.
// Suppose we have the following routing configuration
<Routes>
<Route path="/products/new" element={<NewProduct />} /> {/* Static Path */}
<Route path="/products/:id" element={<ProductDetail />} /> {/* Dynamic Path */}
<Route path="/products/:id/edit" element={<EditProduct />} /> {/* Hybrid Path */}
</Routes>
Prioridade de correspondência (da mais alta à mais baixa):
- Segmentos de caminho estáticos (
new) têm precedência sobre segmentos de parâmetros dinâmicos (:id) - Os caminhos com mais segmentos estáticos têm prioridade sobre os caminhos com menos segmentos estáticos
- Os caminhos com mais segmentos têm prioridade sobre aqueles com menos segmentos.
Portanto, uma solicitação para /products/new corresponde a <NewProduct />, uma solicitação para /products/42 corresponde a <ProductDetail /> e uma solicitação para /products/42/edit corresponde a <EditProduct />. Os desenvolvedores não precisam se preocupar com a ordem — o sistema seleciona automaticamente a “melhor correspondência”.
❓ Perguntas Frequentes
P: Por que ocorre um erro 404 ao atualizar a página após implantar o BrowserRouter no servidor? R: Porque o navegador solicita o caminho específico
/products/detail/1do servidor, mas esse arquivo não existe no servidor. Solução: Configuretry_files $uri $uri/ /index.htmlno Nginx para redirecionar todas as solicitações de rota paraindex.htmle deixe que o React Router cuide da correspondência no front-end. Se não for possível configurar o servidor, mude para o HashRouter (a parte após#não será enviada ao servidor).
P: Qual é a diferença entre a tag
<Link>e a tag nativa<a>? R: Clicar em<a>aciona uma atualização completa da página no navegador, fazendo com que o SPA perca todo o seu estado na memória.<Link>impede a navegação padrão, atualiza a URL por meio da API History e notifica o React Router para renderizar um novo componente — sem atualizar a página nem perder o estado. Em SPAs, use sempreLinkouNavLinkem vez de<a>.
P: Quais são as regras de correspondência de caminhos para as rotas? A ordem das rotas múltiplas faz diferença? R: O React Router v6 utiliza classificação automática para a correspondência (em vez de correspondência sequencial). O sistema atribui automaticamente uma pontuação aos caminhos com base em sua “especificidade”:
/users/newé mais específico do que/users/:ide, portanto, tem precedência.*funciona como um curinga que corresponde a todos os caminhos não correspondidos e é normalmente colocado por último para servir como uma página 404. Por padrão, os caminhos usam correspondência por prefixo; adicionar o atributoendaltera isso para correspondência exata.
P: Qual é a finalidade da rota “index”? R:
<Route index element={...} />define a subrota padrão para a rota pai. Ao acessar a própria rota pai (por exemplo,/products), se a rota pai utilizar um Outlet, o conteúdo da rota “index” será exibido no Outlet. Ela atua como a “página padrão no caminho da rota pai”, evitando que uma área em branco apareça quando o caminho da rota pai é acessado.
P: Quais são as principais diferenças entre o React Router v6 e o v5? R: Há três mudanças importantes na v6: ①
<Routes>+<Route>substitui<Switch>, e o componente Route mapeia automaticamente o caminho mais específico; ② As rotas aninhadas agora usam<Outlet>em vez de renderizar manualmente as rotas filhas; ③useNavigate()substituiuseHistory()—navigate('/path')substituihistory.push('/path')enavigate(-1)substituihistory.goBack(). A API da v6 é mais concisa, mas a migração exige alterações significativas no código.
(5) Caminhos relativos x caminhos absolutos
No roteamento aninhado, o caminho para <Link to="..."> é relativo à rota atual, enquanto <Link to="/..."> é um caminho absoluto. Compreender essa distinção é fundamental para evitar erros de navegação.
// Currently in /products under (ProductsLayout Within the component)
<Link to="list"> {/* → /products/list(Relative Path,After appending it to the current route) */}
<Link to="/list"> {/* → /list(Absolute Path,Replace directly) */}
<Link to="../settings"> {/* → /settings(Parent-level relative path) */}
No roteamento aninhado, se uma rota filha estiver localizada dentro de ProductsLayout, todos os Links dentro dela devem usar caminhos relativos (sem o / inicial). Isso garante que, quando o caminho da rota pai for alterado, os Links da rota filha se adaptem automaticamente.
5. Páginas 404 e padrões de projeto de roteamento
(1) Roteamento com caracteres curinga
path="*" corresponde a todas as rotas não definidas e é a forma padrão de implementar uma página 404. No entanto, no React Router v6, * só pode aparecer no final de uma rota e não pode ser usado da mesma forma que path="/users/*/edit".
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<ProductList />} />
<Route path="/products/:id" element={<ProductDetail />} />
<Route path="/about" element={<About />} />
{/* Wildcard routes must be placed last */}
<Route path="*" element={<NotFound />} />
</Routes>
)
}
function NotFound() {
return (
<div style={{ textAlign: 'center', padding: '40px' }}>
<h1>404</h1>
<p>Sorry, the page you are looking for does not exist.。</p>
<Link to="/">Back to Home</Link>
</div>
)
}
(2) Usos básicos do useNavigate
Embora o useNavigate venha a ser abordado em detalhes no curso avançado, Tom também precisará utilizá-lo em certos cenários durante a fase inicial — como, por exemplo, para redirecionar após a contagem regressiva de uma página de login ou após o envio de um formulário.
import { useNavigate } from 'react-router-dom'
function OrderSuccess() {
const navigate = useNavigate()
const [countdown, setCountdown] = useState(5)
useEffect(() => {
const timer = setInterval(() => {
setCountdown(prev => {
if (prev <= 1) {
clearInterval(timer)
navigate('/orders') // Automatically redirect when the countdown ends
return 0
}
return prev - 1
})
}, 1000)
return () => clearInterval(timer)
}, [navigate])
return (
<div>
<h2>Order Placed Successfully!</h2>
<p>{countdown} You will be automatically redirected to the order page in seconds.</p>
<button onClick={() => navigate('/orders')}>Check it out now</button>
</div>
)
}
▶ Exemplo 5: Um painel de administração que reúne todos os recursos
Reúna todos os conceitos que você aprendeu nesta lição — BrowserRouter, rotas, rotas aninhadas, NavLink, useParams e páginas 404 — para construir a estrutura básica de um painel de administração completo.
import { BrowserRouter, Routes, Route, NavLink, Outlet, useParams } from 'react-router-dom'
import './App.css'
// Layout Components
function AdminLayout() {
return (
<div className="admin-container">
<header className="admin-header">
<h1>Tom E-commerce Management Backend</h1>
</header>
<div className="admin-body">
<nav className="admin-sidebar">
<NavLink to="/" end>Dashboard</NavLink>
<NavLink to="/products">Product Management</NavLink>
<NavLink to="/orders">Order Management</NavLink>
<NavLink to="/settings">System Settings</NavLink>
</nav>
<main className="admin-content">
<Outlet />
</main>
</div>
</div>
)
}
// Page Components
function Dashboard() {
return <h2>Welcome back,Tom!Number of Orders Today:42</h2>
}
function ProductsLayout() {
return (
<div>
<h2>Product Management</h2>
<nav>
<NavLink to="list">Product List</NavLink>
<NavLink to="add">Add Item</NavLink>
</nav>
<Outlet />
</div>
)
}
function ProductList() {
return <p>The product list is displayed here...</p>
}
function AddProduct() {
return <p>The form for adding products is displayed here....</p>
}
function Orders() {
return <h2>Order Management</h2>
}
function Settings() {
return <h2>System Settings</h2>
}
function NotFound() {
return <h2>404 — Page Not Found</h2>
}
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<AdminLayout />}>
<Route index element={<Dashboard />} />
<Route path="products" element={<ProductsLayout />}>
<Route index element={<ProductList />} />
<Route path="list" element={<ProductList />} />
<Route path="add" element={<AddProduct />} />
</Route>
<Route path="orders" element={<Orders />} />
<Route path="settings" element={<Settings />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
)
}
Características arquitetônicas: O aplicativo inteiro consiste em apenas um <BrowserRouter> e um <Routes> de nível superior. O AdminLayout funciona como um layout global que incorpora todos os componentes da página por meio de outlets. Esse padrão de “rota única + layout aninhado” é a arquitetura padrão para aplicativos React de médio porte.
📖 Resumo
- O BrowserRouter se baseia na API History, enquanto o HashRouter se baseia em hashes de URL; recomenda-se o uso do primeiro (requer suporte do servidor)
- O componente Routes é responsável pela correspondência; o componente Route define o mapeamento entre caminhos e componentes
- Link: Para navegação declarativa; o NavLink oferece detecção de estado ativo (callback isActive)
- O
useParamsextrai parâmetros dinâmicos da URL e suporta parâmetros com vários segmentos (:id,:catId/:prodId) - As rotas aninhadas utilizam outlets para reutilizar layouts, e a rota “index” fornece o conteúdo padrão para o caminho pai
- Ao implantar o BrowserRouter em um ambiente de produção, é necessário configurar as regras de reescrita de URLs do servidor.
- No roteamento aninhado, esteja ciente da diferença entre caminhos relativos (sem o
/no início) e caminhos absolutos (com o/no início)
📝 Exercícios
- Crie um painel de administração de 4 páginas: Página inicial, Lista de usuários, Detalhes do usuário (recupera o ID do usuário usando
useParams) e página “Sobre”. UseLinkpara a navegação e certifique-se de queNavLinktenha um estilo ativo. - Adicione rotas aninhadas à página da lista de usuários:
/usersexibe a lista de usuários e/users/:idexibe os detalhes do usuário; ambas compartilham um componente de layout com um cabeçalho (usando um Outlet). - Adicione uma página 404 ao final da tabela de roteamento para exibir uma mensagem amigável quando um usuário acessar um caminho inexistente.