<h2>Introdução ao React Router</h2>
<p>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.</p>
<p>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.</p>
<h2>Configuração Básica e Rotas Estáticas</h2>
<h3>Setup Inicial</h3>
<p>Comece instalando React Router v6 (versão atual estável):</p>
<pre><code class="language-bash">npm install react-router-dom</code></pre>
<p>A configuração envolve envolver sua aplicação com <code>BrowserRouter</code> e definir rotas usando <code>Routes</code> e <code>Route</code>:</p>
<pre><code class="language-jsx">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>
);
}</code></pre>
<p>Cada rota mapeia um caminho (<code>path</code>) a um componente (<code>element</code>). 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.</p>
<h3>Navegação com Link e useNavigate</h3>
<p>Para navegar sem recarregar, use o componente <code>Link</code> ou o hook <code>useNavigate</code>. <code>Link</code> é ideal para navegação declarativa em componentes, enquanto <code>useNavigate</code> oferece controle programático:</p>
<pre><code class="language-jsx">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>
);
}</code></pre>
<h2>Rotas Dinâmicas e Parâmetros</h2>
<h3>Parâmetros de URL</h3>
<p>Rotas dinâmicas capturam partes variáveis da URL usando dois-pontos (<code>:paramName</code>). Acesse-os com o hook <code>useParams</code>:</p>
<pre><code class="language-jsx">// 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>
);
}</code></pre>
<h3>Query Strings</h3>
<p>Para parâmetros opcionais na query string (ex: <code>/products?sort=price&filter=active</code>), use <code>useSearchParams</code>:</p>
<pre><code class="language-jsx">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>
);
}</code></pre>
<h2>Proteção de Rotas e Autenticação</h2>
<h3>PrivateRoute com Contexto</h3>
<p>Rotas protegidas garantem que apenas usuários autenticados acessem certas páginas. Implemente um contexto de autenticação e um componente wrapper:</p>
<pre><code class="language-jsx">// 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></code></pre>
<h3>Proteção Baseada em Roles</h3>
<p>Para controle granular, valide permissões dentro da rota:</p>
<pre><code class="language-jsx">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>}
/></code></pre>
<h2>Recursos Avançados</h2>
<h3>Layouts Aninhados</h3>
<p>Use layouts compartilhados para múltiplas rotas com <code>Outlet</code>:</p>
<pre><code class="language-jsx">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></code></pre>
<h3>Tratamento de Rotas Não Encontradas</h3>
<p>Adicione um catch-all no final para páginas 404:</p>
<pre><code class="language-jsx"><Route path="*" element={<NotFound />} /></code></pre>
<h2>Conclusão</h2>
<p>React Router v6 simplifica navegação em SPAs através de três pilares: <strong>rotas estáticas e dinâmicas</strong> para mapear URLs a componentes, <strong>parâmetros e query strings</strong> para compartilhar dados entre telas, e <strong>proteção via contexto e componentes wrapper</strong> para segurança. Pratique combinando esses conceitos em um projeto real — um e-commerce ou dashboard de admin são ótimos casos de uso.</p>
<p>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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://reactrouter.com/" target="_blank" rel="noopener noreferrer">React Router Documentation</a></li>
<li><a href="https://reactrouter.com/en/main/guides/upgrading-from-v5" target="_blank" rel="noopener noreferrer">React Router v6 Upgrade Guide</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Glossary/SPA" target="_blank" rel="noopener noreferrer">MDN: Client-side Routing</a></li>
<li><a href="https://react.dev/reference/react/useContext" target="_blank" rel="noopener noreferrer">React Context API</a></li>
<li><a href="https://www.freecodecamp.org/news/react-router-v6-tutorial/" target="_blank" rel="noopener noreferrer">freeCodeCamp: React Router Tutorial</a></li>
</ul>