O que Todo Dev Deve Saber sobre React Router: Navegação, Rotas Dinâmicas e Proteção de Rotas Já leu

Introdução ao React Router React Router é a biblioteca padrão para navegação em aplicações React modernas. Ela permite criar uma experiência de usuário fluida sem recarregar a página, mantendo o histórico do navegador e sincronizando a URL com o estado da aplicação. Dominar Router é essencial para construir SPAs (Single Page Applications) profissionais e escaláveis. Neste artigo, vamos cobrir desde configuração básica até proteção de rotas avançada. Você aprenderá a criar navegações eficientes, trabalhar com parâmetros dinâmicos e implementar autenticação em rotas privadas. Assumo que você já conhece React hooks e componentes funcionais. Configuração Básica e Rotas Estáticas Setup Inicial Comece instalando React Router v6 (versão atual estável): A configuração envolve envolver sua aplicação com e definir rotas usando e : Cada rota mapeia um caminho ( ) a um componente ( ). Quando o usuário navega para uma URL, React Router renderiza o componente correspondente sem recarregar a página. A ordem das rotas importa: React Router usa a primeira

Introdução ao React Router

React Router é a biblioteca padrão para navegação em aplicações React modernas. Ela permite criar uma experiência de usuário fluida sem recarregar a página, mantendo o histórico do navegador e sincronizando a URL com o estado da aplicação. Dominar Router é essencial para construir SPAs (Single Page Applications) profissionais e escaláveis.

Neste artigo, vamos cobrir desde configuração básica até proteção de rotas avançada. Você aprenderá a criar navegações eficientes, trabalhar com parâmetros dinâmicos e implementar autenticação em rotas privadas. Assumo que você já conhece React hooks e componentes funcionais.

Configuração Básica e Rotas Estáticas

Setup Inicial

Comece instalando React Router v6 (versão atual estável):

npm install react-router-dom

A configuração envolve envolver sua aplicação com BrowserRouter e definir rotas usando Routes e Route:

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

export default function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </Router>
  );
}

Cada rota mapeia um caminho (path) a um componente (element). Quando o usuário navega para uma URL, React Router renderiza o componente correspondente sem recarregar a página. A ordem das rotas importa: React Router usa a primeira que encontra correspondência.

Navegação com Link e useNavigate

Para navegar sem recarregar, use o componente Link ou o hook useNavigate. Link é ideal para navegação declarativa em componentes, enquanto useNavigate oferece controle programático:

import { Link, useNavigate } from 'react-router-dom';

export default function Navbar() {
  const navigate = useNavigate();

  const handleLogout = () => {
    sessionStorage.removeItem('token');
    navigate('/login');
  };

  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">Sobre</Link>
      <button onClick={handleLogout}>Logout</button>
    </nav>
  );
}

Rotas Dinâmicas e Parâmetros

Parâmetros de URL

Rotas dinâmicas capturam partes variáveis da URL usando dois-pontos (:paramName). Acesse-os com o hook useParams:

// Em App.jsx
<Route path="/product/:id" element={<ProductDetail />} />

// Em ProductDetail.jsx
import { useParams } from 'react-router-dom';

export default function ProductDetail() {
  const { id } = useParams();
  const [product, setProduct] = React.useState(null);

  React.useEffect(() => {
    fetch(`/api/products/${id}`)
      .then(res => res.json())
      .then(data => setProduct(data));
  }, [id]);

  if (!product) return <div>Carregando...</div>;

  return (
    <div>
      <h1>{product.name}</h1>
      <p>Preço: R$ {product.price}</p>
    </div>
  );
}

Query Strings

Para parâmetros opcionais na query string (ex: /products?sort=price&filter=active), use useSearchParams:

import { useSearchParams } from 'react-router-dom';

export default function Products() {
  const [searchParams, setSearchParams] = useSearchParams();
  const sort = searchParams.get('sort') || 'name';
  const filter = searchParams.get('filter') || 'all';

  const handleFilterChange = (newSort) => {
    setSearchParams({ sort: newSort, filter });
  };

  return (
    <div>
      <button onClick={() => handleFilterChange('price')}>
        Ordenar por Preço
      </button>
      <p>Ordenação atual: {sort}</p>
    </div>
  );
}

Proteção de Rotas e Autenticação

PrivateRoute com Contexto

Rotas protegidas garantem que apenas usuários autenticados acessem certas páginas. Implemente um contexto de autenticação e um componente wrapper:

// AuthContext.jsx
import React, { createContext, useState, useEffect } from 'react';

export const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const token = localStorage.getItem('token');
    if (token) {
      // Validar token com backend
      fetch('/api/auth/validate', {
        headers: { Authorization: `Bearer ${token}` }
      })
        .then(res => res.json())
        .then(data => setUser(data))
        .catch(() => setUser(null))
        .finally(() => setLoading(false));
    } else {
      setLoading(false);
    }
  }, []);

  return (
    <AuthContext.Provider value={{ user, setUser, loading }}>
      {children}
    </AuthContext.Provider>
  );
}

// PrivateRoute.jsx
import { Navigate } from 'react-router-dom';
import { useContext } from 'react';
import { AuthContext } from './AuthContext';

export function PrivateRoute({ children }) {
  const { user, loading } = useContext(AuthContext);

  if (loading) return <div>Carregando...</div>;

  return user ? children : <Navigate to="/login" />;
}

// App.jsx
<AuthProvider>
  <Router>
    <Routes>
      <Route path="/login" element={<Login />} />
      <Route 
        path="/dashboard" 
        element={<PrivateRoute><Dashboard /></PrivateRoute>} 
      />
    </Routes>
  </Router>
</AuthProvider>

Proteção Baseada em Roles

Para controle granular, valide permissões dentro da rota:

export function AdminRoute({ children }) {
  const { user, loading } = useContext(AuthContext);

  if (loading) return <div>Carregando...</div>;

  if (!user) return <Navigate to="/login" />;
  if (user.role !== 'admin') return <Navigate to="/unauthorized" />;

  return children;
}

// Uso
<Route 
  path="/admin" 
  element={<AdminRoute><AdminPanel /></AdminRoute>} 
/>

Recursos Avançados

Layouts Aninhados

Use layouts compartilhados para múltiplas rotas com Outlet:

import { Outlet } from 'react-router-dom';

export function Layout() {
  return (
    <div>
      <Navbar />
      <Outlet /> {/* Renderiza a rota filha aqui */}
      <Footer />
    </div>
  );
}

// Em App.jsx
<Route element={<Layout />}>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
</Route>

Tratamento de Rotas Não Encontradas

Adicione um catch-all no final para páginas 404:

<Route path="*" element={<NotFound />} />

Conclusão

React Router v6 simplifica navegação em SPAs através de três pilares: rotas estáticas e dinâmicas para mapear URLs a componentes, parâmetros e query strings para compartilhar dados entre telas, e proteção via contexto e componentes wrapper para segurança. Pratique combinando esses conceitos em um projeto real — um e-commerce ou dashboard de admin são ótimos casos de uso.

A chave para dominar Router é entender que ela sincroniza três elementos: URL, histórico do navegador e estado da aplicação. Domine isso e você construirá navegações robustas e profissionais.

Referências


Artigos relacionados