Rutas Dinámicas, Protegidas y 404
Volver a clases
Frontend Development●●Intermedio

Rutas Dinámicas, Protegidas y 404

120 min

Parametros, rutas anidadas, protección y redirecciones.

Rutas dinámicas y parámetros

  • useParams permite 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).
  • Route con index define la pantalla por defecto del layout.
  • Las rutas hijas usan paths relativos, evitando duplicar prefijos.
  • Útil para secciones como /dashboard, /cuenta, /admin.
  • useNavigate redirige después de acciones (login, submit, logout).
  • replace: true evita que el usuario vuelva a la pantalla anterior con back.

Query params

  • useSearchParams administra 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

  • Navigate redirige según autenticación.
  • Se puede guardar la ruta previa en state para 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.

jsx
1function 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:

jsx
1const 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

jsx
1<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

javascript
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

javascript
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

javascript
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ácticaIntermedio1 min🟡 IA con bitácora

Práctica guiada - Detalle de producto

Práctica

Lista de productos con ruta dinámica y detalle por id.

Desafío de Código

EjercicioIntermedio15 min🔴 Sin IA

Ejercicios - Auth y filtros

Ejercicios

(1) Login con redirección, (2) filtro por query params, (3) pantalla 404.

Documentación Oficial

DocumentaciónIntermedio15 min

useSearchParams

Guía para manejar query params en React Router.