Pular para o conteúdo
af aprenda frontend
módulo 06 componentes

Roteamento com React Router.

Por que SPAs precisam de um router, como configurar o React Router v7 e conectar as páginas do blog com Link, useParams e useNavigate.

O blog construído até agora alterna entre HomePage e ArticlePage por estado — a URL nunca muda, o botão voltar não funciona, e não é possível compartilhar o link de um artigo específico. Roteamento resolve exatamente isso: cada página recebe uma URL, a navegação passa pelo histórico do browser, e qualquer link pode ser compartilhado diretamente.

Por que roteamento existe em aplicações React

Sites tradicionais têm múltiplos arquivos HTML no servidor — clicar em um link faz o browser requisitar um novo arquivo e renderizar a página do zero.

React apps são SPAs (Single Page Applications): o servidor entrega um único index.html, e o JavaScript substitui o conteúdo sem requisições adicionais. Isso é mais rápido — mas cria um problema: sem intervenção, a URL não muda com a navegação. O botão voltar não vai para a tela anterior — vai para a URL anterior, que provavelmente é a mesma. Links para páginas específicas não funcionam.

tsx
// sem React Router: troca de página é estado
const [pagina, setPagina] = useState<"home" | "artigo">("home");

return pagina === "home"
  ? <HomePage onVerArtigo={() => setPagina("artigo")} />
  : <ArticlePage />;

// problemas:
// - URL nunca muda — /artigos/css-em-geral não existe
// - botão voltar do browser não funciona
// - não dá para compartilhar link de um artigo específico
SPA sem router — navegação por estado, URL estática.

React Router intercepta a navegação, atualiza a URL com a History API do browser e renderiza o componente correto — sem recarregar a página.

Instalação e configuração

bash
npm install react-router
Instalar o React Router.

A partir do React Router v7, o pacote foi consolidado em react-router — o react-router-dom foi descontinuado. A API usa createBrowserRouter — uma função que recebe a lista de rotas e retorna um objeto de router. O RouterProvider monta esse router na raiz da aplicação:

tsx
import { createBrowserRouter, RouterProvider } from "react-router";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { HomePage } from "./pages/HomePage";
import { ArticlePage } from "./pages/ArticlePage";
import { PaginaNaoEncontrada } from "./pages/PaginaNaoEncontrada";

const router = createBrowserRouter([
  { path: "/", element: <HomePage /> },
  { path: "/artigos/:slug", element: <ArticlePage /> },
  { path: "*", element: <PaginaNaoEncontrada /> },
]);

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <RouterProvider router={router} />
  </StrictMode>
);
main.tsx — configurar o router e montar a aplicação.

RouterProvider substitui <App /> como raiz. Todos os componentes dentro dele têm acesso aos hooks do React Router.

Definindo rotas

Cada rota é um objeto com path e element. O path é um padrão de URL:

tsx
const router = createBrowserRouter([
  // rota literal — corresponde exatamente a "/"
  { path: "/", element: <HomePage /> },

  // rota com parâmetro dinâmico — ":slug" captura qualquer segmento
  // /artigos/css-em-geral → slug = "css-em-geral"
  // /artigos/react-hooks  → slug = "react-hooks"
  { path: "/artigos/:slug", element: <ArticlePage /> },

  // wildcard — captura qualquer rota não definida acima
  { path: "*", element: <PaginaNaoEncontrada /> },
]);
Padrões de rota — literal, dinâmico e wildcard.

Dentro de componentes, use <Link> do React Router no lugar de <a>. <Link> gera um <a> no HTML, mas intercepta o clique e chama o router em vez de deixar o browser navegar:

tsx
import { Link } from "react-router";

interface Props {
  artigo: Artigo;
}

export function ArticleCard({ artigo }: Props) {
  return (
    <article className="card-artigo">
      <h2>{artigo.titulo}</h2>
      <p>{artigo.descricao}</p>
      {/* Link gera <a> mas intercepta o clique — sem reload */}
      <Link to={`/artigos/${artigo.slug}`}>Ler artigo →</Link>
    </article>
  );
}
ArticleCard.tsx — Link navega sem recarregar a página.

<NavLink> é uma variante que aplica automaticamente uma classe quando a rota está ativa — útil para menus:

tsx
import { NavLink } from "react-router";

export function Header() {
  return (
    <nav>
      {/* className recebe função: isActive indica se a rota está ativa */}
      <NavLink
        to="/"
        end
        className={({ isActive }) => isActive ? "nav-link ativo" : "nav-link"}
      >
        Início
      </NavLink>
      {/* end: ativa só em "/", não em "/artigos/qualquer-coisa" */}
    </nav>
  );
}
Header.tsx — NavLink com classe active automática.

Parâmetros de URL com useParams

Quando uma rota tem parâmetros (:slug, :id), o componente os acessa com useParams:

tsx
import { useParams } from "react-router";
import { useArtigo } from "../hooks/useArtigo";

export function ArticlePage() {
  // slug vem da URL: /artigos/css-em-geral → slug = "css-em-geral"
  const { slug } = useParams<{ slug: string }>();

  const { artigo, carregando, erro } = useArtigo(slug!);

  if (carregando) return <p>Carregando artigo...</p>;
  if (erro || !artigo) return <p>Artigo não encontrado.</p>;

  return (
    <main>
      <h1>{artigo.titulo}</h1>
      <ArticleBody conteudo={artigo.conteudo} />
      <LikeButton artigoId={artigo.id} />
    </main>
  );
}
ArticlePage.tsx — ler :slug da URL com useParams.

O tipo genérico <{ slug: string }> em useParams garante que o TypeScript sabe que slug existe e é string — sem necessidade de verificação manual.

Quando a navegação deve acontecer em código — após submit de formulário, após login, ao detectar um erro — use useNavigate:

tsx
import { useNavigate } from "react-router";
import { useState } from "react";

export function BuscaRapida() {
  const navigate = useNavigate();
  const [query, setQuery] = useState("");

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    navigate(`/?busca=${encodeURIComponent(query)}`);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Buscar artigos..."
      />
      <button type="submit">Buscar</button>
    </form>
  );
}
Redirecionar após submit de formulário com useNavigate.

navigate(-1) navega para a entrada anterior no histórico — equivalente ao botão voltar do browser.

Resumo

  • SPAs sem router: URL estática, botão voltar quebrado, links para páginas específicas não funcionam.
  • npm install react-router + createBrowserRouter + RouterProvider: configuração do React Router v7. O pacote foi consolidado em react-router — importe tudo de lá.
  • Cada rota é { path, element }. Parâmetros dinâmicos com :nome. Wildcard * para páginas não encontradas.
  • <Link to="...">: navegação sem reload. <NavLink>: com classe active automática — útil em menus.
  • useParams<{ slug: string }>(): acessa parâmetros dinâmicos da URL dentro do componente.
  • useNavigate(): navegação em código — após submit, login ou redirecionamento condicional.
/ checkpoint verifique seu entendimento
questão 1 de 3

Por que usar <a href='/artigos'> comum em uma SPA React causa problema?