Parametros, rutas anidadas, protección y redirecciones.
Rutas dinámicas y parámetros
useParamspermite leer identificadores desde la URL.- Ideal para perfiles, productos o detalle de posts.
- Se pueden usar múltiples parámetros:
/categorias/:slug/productos/:id. - Conviene validar y transformar tipos (por ejemplo,
Number(id)) antes de usar el valor. - Si el id no existe, mostrar un estado "no encontrado" o redirigir.
Rutas anidadas y layouts
- Permiten compartir un layout común con
Outlet(sidebar, header, tabs). Routeconindexdefine la pantalla por defecto del layout.- Las rutas hijas usan paths relativos, evitando duplicar prefijos.
- Útil para secciones como
/dashboard,/cuenta,/admin.
Navegación programática
useNavigateredirige después de acciones (login, submit, logout).replace: trueevita que el usuario vuelva a la pantalla anterior con back.
Query params
useSearchParamsadministra filtros, orden y paginación.- Mantiene el estado en la URL.
- Se recomienda definir valores por defecto para evitar
null. - Útil para sincronizar UI (filtros) con la URL y compartir resultados.
Rutas protegidas y 404
Navigateredirige según autenticación.- Se puede guardar la ruta previa en
statepara volver después del login. - Ruta
*captura páginas inexistentes. - En rutas anidadas, un
*interno permite 404 por sección. - Mostrar un CTA para volver al home o a la sección principal.
La ruta protegida, completa
Este es el patrón que vas a necesitar en tu proyecto si tiene login. La idea: un componente envoltorio que decide si deja pasar o redirige.
jsx1function RutaProtegida({ children }) { 2 const { usuario, cargando } = useAuth(); 3 const location = useLocation(); 4 5 // 🚨 El paso que casi todos olvidan: mientras se valida la sesión, 6 // usuario es null y redirigirías a un usuario que SÍ está logueado. 7 if (cargando) return <Spinner />; 8 9 if (!usuario) { 10 // Guardamos de dónde venía para devolverlo ahí después del login 11 return <Navigate to="/login" replace state={{ from: location }} />; 12 } 13 14 return children; 15} 16 17// Uso: 18<Route 19 path="/dashboard" 20 element={ 21 <RutaProtegida> 22 <Dashboard /> 23 </RutaProtegida> 24 } 25/>
Y en el login, para completar el círculo:
jsx1const location = useLocation(); 2const navigate = useNavigate(); 3const destino = location.state?.from?.pathname || "/"; 4 5async function onSubmit() { 6 await iniciarSesion(datos); 7 navigate(destino, { replace: true }); // replace: no vuelve al login con "atrás" 8}
Dos detalles que valen tu calificación en la defensa: el estado de carga (sin él expulsas a usuarios válidos en cada recarga) y el replace: true (sin él, el botón atrás regresa al login y el usuario queda atrapado en un ciclo).
⚠️ Una ruta protegida en el frontend es experiencia de usuario, no seguridad. Cualquiera puede abrir las DevTools y saltársela. La seguridad real siempre vive en el servidor: si tu API no valida quién pide los datos, tu app es pública aunque la ruta esté "protegida".
El 404 y el orden de las rutas
jsx1<Routes> 2 <Route path="/" element={<Home />} /> 3 <Route path="/productos/:id" element={<Detalle />} /> 4 <Route path="*" element={<NoEncontrado />} /> {/* siempre al final */} 5</Routes>
La ruta * captura todo lo que no coincidió. React Router elige la más específica, así que el orden en el archivo no la rompe — pero escribirla al final es la convención que hace el código legible.
Un caso que sí se olvida: cuando useParams te da un id que no existe en tus datos (alguien escribió /productos/9999 a mano). Eso no es un 404 de ruta: la ruta coincidió. Hay que manejarlo dentro del componente con un estado de "no encontrado".
Ejemplos de Código
3 ejemplos
Parametros en URL
1import { Routes, Route, useParams } from "react-router-dom";
2
3function UserProfile() {
4 const { id } = useParams();
5 return <div>Perfil: {id}</div>;
6}
7
8function App() {
9 return (
10 <Routes>
11 <Route path="/users/:id" element={<UserProfile />} />
12 </Routes>
13 );
14}Protección por auth
1import { Navigate } from "react-router-dom";
2
3function ProtectedRoute({ children }) {
4 const isAuth = Boolean(localStorage.getItem("token"));
5 return isAuth ? children : <Navigate to="/login" replace />;
6}Ruta catch-all
1import { Routes, Route } from "react-router-dom";
2import NotFound from "./pages/NotFound";
3
4function App() {
5 return (
6 <Routes>
7 <Route path="/" element={<Home />} />
8 <Route path="*" element={<NotFound />} />
9 </Routes>
10 );
11}Recursos
3 recursos disponibles
¡Hora de Practicar!
Práctica guiada - Detalle de producto
Práctica
Lista de productos con ruta dinámica y detalle por id.
Desafío de Código
Ejercicios - Auth y filtros
Ejercicios
(1) Login con redirección, (2) filtro por query params, (3) pantalla 404.
Documentación Oficial
useSearchParams
Guía para manejar query params en React Router.