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 useState para 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



2. Diagramas conceituais

100%
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

JSX
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
▶ Experimente

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.

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

JSX 📖 Somente leitura
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>
  )
}
42 linhas de lógica (limite de 40, somente leitura)

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

JSX 📖 Somente leitura
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>
  )
}
72 linhas de lógica (limite de 40, somente leitura)

Lógica de fluxo: Acessar /products/listProductsLayout (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.

JSX
function UserDetail() {
  const { userId, postId } = useParams()
  return <p>User {userId} Article {postId}</p>
}
// URL: /users/42/posts/99 → userId=42, postId=99
▶ Experimente

▶ Exemplo 4: Página de detalhes do produto

JSX
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>
  )
}
▶ Experimente

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:

JSX
// 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>
}
▶ Experimente

(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:

JSX
// 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>
}
▶ Experimente

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.

JSX
// 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>
▶ Experimente

Prioridade de correspondência (da mais alta à mais baixa):

  1. Segmentos de caminho estáticos (new) têm precedência sobre segmentos de parâmetros dinâmicos (:id)
  2. Os caminhos com mais segmentos estáticos têm prioridade sobre os caminhos com menos segmentos estáticos
  3. 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/1 do servidor, mas esse arquivo não existe no servidor. Solução: Configure try_files $uri $uri/ /index.html no Nginx para redirecionar todas as solicitações de rota para index.html e 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 sempre Link ou NavLink em 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/:id e, 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 atributo end altera 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() substitui useHistory()navigate('/path') substitui history.push('/path') e navigate(-1) substitui history.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.

JSX
// 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) */}
▶ Experimente

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".

JSX
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>
  )
}
▶ Experimente

(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.

JSX
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>
  )
}
▶ Experimente

▶ 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.

JSX 📖 Somente leitura
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>
  )
}
71 linhas de lógica (limite de 40, somente leitura)

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


📝 Exercícios

  1. 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”. Use Link para a navegação e certifique-se de que NavLink tenha um estilo ativo.
  2. Adicione rotas aninhadas à página da lista de usuários: /users exibe a lista de usuários e /users/:id exibe os detalhes do usuário; ambas compartilham um componente de layout com um cabeçalho (usando um Outlet).
  3. 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.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%